@upstart.gg/vite-plugins 0.0.38 → 0.0.40

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 (64) hide show
  1. package/dist/upstart-editor-api.d.ts +79 -0
  2. package/dist/upstart-editor-api.d.ts.map +1 -0
  3. package/dist/upstart-editor-api.js +208 -0
  4. package/dist/upstart-editor-api.js.map +1 -0
  5. package/dist/vite-plugin-upstart-attrs.d.ts +3 -3
  6. package/dist/vite-plugin-upstart-attrs.d.ts.map +1 -1
  7. package/dist/vite-plugin-upstart-attrs.js +227 -25
  8. package/dist/vite-plugin-upstart-attrs.js.map +1 -1
  9. package/dist/vite-plugin-upstart-branding/plugin.d.ts +17 -0
  10. package/dist/vite-plugin-upstart-branding/plugin.d.ts.map +1 -0
  11. package/dist/vite-plugin-upstart-branding/plugin.js +41 -0
  12. package/dist/vite-plugin-upstart-branding/plugin.js.map +1 -0
  13. package/dist/vite-plugin-upstart-branding/runtime.d.ts +10 -0
  14. package/dist/vite-plugin-upstart-branding/runtime.d.ts.map +1 -0
  15. package/dist/vite-plugin-upstart-branding/runtime.js +118 -0
  16. package/dist/vite-plugin-upstart-branding/runtime.js.map +1 -0
  17. package/dist/vite-plugin-upstart-branding/types.d.ts +14 -0
  18. package/dist/vite-plugin-upstart-branding/types.d.ts.map +1 -0
  19. package/dist/vite-plugin-upstart-branding/types.js +1 -0
  20. package/dist/vite-plugin-upstart-editor/plugin.d.ts +3 -3
  21. package/dist/vite-plugin-upstart-editor/plugin.d.ts.map +1 -1
  22. package/dist/vite-plugin-upstart-editor/plugin.js +3 -16
  23. package/dist/vite-plugin-upstart-editor/plugin.js.map +1 -1
  24. package/dist/vite-plugin-upstart-editor/runtime/click-handler.js +25 -11
  25. package/dist/vite-plugin-upstart-editor/runtime/click-handler.js.map +1 -1
  26. package/dist/vite-plugin-upstart-editor/runtime/error-handler.d.ts +5 -0
  27. package/dist/vite-plugin-upstart-editor/runtime/error-handler.d.ts.map +1 -0
  28. package/dist/vite-plugin-upstart-editor/runtime/error-handler.js +16 -0
  29. package/dist/vite-plugin-upstart-editor/runtime/error-handler.js.map +1 -0
  30. package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js +1 -1
  31. package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js.map +1 -1
  32. package/dist/vite-plugin-upstart-editor/runtime/index.d.ts +2 -1
  33. package/dist/vite-plugin-upstart-editor/runtime/index.d.ts.map +1 -1
  34. package/dist/vite-plugin-upstart-editor/runtime/index.js +42 -7
  35. package/dist/vite-plugin-upstart-editor/runtime/index.js.map +1 -1
  36. package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts +6 -1
  37. package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts.map +1 -1
  38. package/dist/vite-plugin-upstart-editor/runtime/text-editor.js +423 -129
  39. package/dist/vite-plugin-upstart-editor/runtime/text-editor.js.map +1 -1
  40. package/dist/vite-plugin-upstart-editor/runtime/types.d.ts +18 -10
  41. package/dist/vite-plugin-upstart-editor/runtime/types.d.ts.map +1 -1
  42. package/dist/vite-plugin-upstart-theme.d.ts +3 -3
  43. package/dist/vite-plugin-upstart-theme.d.ts.map +1 -1
  44. package/dist/vite-plugin-upstart-theme.js +1 -3
  45. package/dist/vite-plugin-upstart-theme.js.map +1 -1
  46. package/package.json +12 -4
  47. package/src/tests/upstart-editor-api.test.ts +98 -174
  48. package/src/tests/vite-plugin-upstart-attrs.test.ts +408 -105
  49. package/src/tests/vite-plugin-upstart-branding.test.ts +90 -0
  50. package/src/tests/vite-plugin-upstart-editor.test.ts +1 -2
  51. package/src/upstart-editor-api.ts +90 -29
  52. package/src/vite-plugin-upstart-attrs.ts +376 -38
  53. package/src/vite-plugin-upstart-branding/plugin.ts +59 -0
  54. package/src/vite-plugin-upstart-branding/runtime.ts +128 -0
  55. package/src/vite-plugin-upstart-branding/types.ts +10 -0
  56. package/src/vite-plugin-upstart-editor/plugin.ts +4 -19
  57. package/src/vite-plugin-upstart-editor/runtime/click-handler.ts +25 -12
  58. package/src/vite-plugin-upstart-editor/runtime/error-handler.ts +12 -0
  59. package/src/vite-plugin-upstart-editor/runtime/hover-overlay.ts +1 -1
  60. package/src/vite-plugin-upstart-editor/runtime/index.ts +39 -5
  61. package/src/vite-plugin-upstart-editor/runtime/text-editor.ts +518 -141
  62. package/src/vite-plugin-upstart-editor/runtime/types.ts +18 -4
  63. package/src/vite-plugin-upstart-theme.ts +0 -3
  64. package/src/vite-plugin-upstart-editor/PLAN.md +0 -1391
@@ -1 +1 @@
1
- {"version":3,"file":"text-editor.js","names":["DEFAULT_OPTIONS: Required<UpstartEditorOptions>","extensions: Extension[]"],"sources":["../../../src/vite-plugin-upstart-editor/runtime/text-editor.ts"],"sourcesContent":["import { Editor } from \"@tiptap/core\";\nimport type { Extension } from \"@tiptap/core\";\nimport { BubbleMenu } from \"@tiptap/extension-bubble-menu\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { getCurrentMode } from \"./index.js\";\nimport { sendToParent } from \"./utils.js\";\nimport type { EditorInstance, UpstartEditorOptions } from \"./types.js\";\n\nconst DEFAULT_OPTIONS: Required<UpstartEditorOptions> = {\n richTextElements: [\"p\", \"div\", \"article\", \"section\"],\n plainTextElements: [\"button\", \"a\", \"span\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"label\"],\n bubbleMenu: true,\n placeholder: \"Start typing...\",\n autoSaveDelay: 1000,\n};\n\nconst activeEditors = new Map<string, EditorInstance>();\nconst saveTimeouts = new Map<string, number>();\nconst styleCache = new WeakMap<\n HTMLElement,\n { outline: string; outlineOffset: string; cursor: string; transition: string }\n>();\nlet isInitialized = false;\nlet shortcutsRegistered = false;\n\n/**\n * Initialize TipTap text editing for elements marked as editable.\n */\nexport function initTextEditor(options: UpstartEditorOptions = {}): void {\n if (typeof window === \"undefined\") {\n return;\n }\n\n if (isInitialized) {\n return;\n }\n\n try {\n const resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n const editables = document.querySelectorAll<HTMLElement>('[data-upstart-editable-text=\"true\"]');\n\n editables.forEach((element) => setupEditableElement(element, resolvedOptions));\n\n registerKeyboardShortcuts();\n isInitialized = true;\n\n console.log(\"[Upstart Editor] Text editor initialized\");\n } catch (error) {\n console.error(\"[Upstart Editor] Failed to initialize text editor:\", error);\n sendToParent({\n type: \"editor-error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n}\n\n/**\n * Destroy all active editors.\n */\nexport function destroyAllActiveEditors(): void {\n for (const hash of activeEditors.keys()) {\n destroyEditor(hash);\n }\n}\n\nfunction setupEditableElement(element: HTMLElement, options: Required<UpstartEditorOptions>): void {\n const hash = getEditableHash(element);\n if (!hash) {\n return;\n }\n\n cacheStyles(element);\n element.style.transition = \"outline 0.15s ease\";\n\n element.addEventListener(\"dblclick\", (event) => {\n if (getCurrentMode() !== \"edit\") {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n if (activeEditors.has(hash)) {\n return;\n }\n\n activateEditor(element, hash, options);\n });\n\n element.addEventListener(\"mouseenter\", () => {\n if (getCurrentMode() !== \"edit\") {\n return;\n }\n\n if (!activeEditors.has(hash)) {\n applyHoverStyles(element);\n }\n });\n\n element.addEventListener(\"mouseleave\", () => {\n if (!activeEditors.has(hash)) {\n restoreStyles(element);\n }\n });\n}\n\nfunction activateEditor(element: HTMLElement, hash: string, options: Required<UpstartEditorOptions>): void {\n const isRichText = shouldUseRichText(element, options);\n const editor = isRichText\n ? createRichTextEditor(element, hash, options)\n : createPlainTextEditor(element, hash, options);\n\n applyActiveStyles(element);\n activeEditors.set(hash, { editor, element, hash });\n}\n\nfunction createPlainTextEditor(\n element: HTMLElement,\n hash: string,\n options: Required<UpstartEditorOptions>,\n): Editor {\n return new Editor({\n element,\n extensions: [\n StarterKit.configure({\n heading: false,\n bold: false,\n italic: false,\n strike: false,\n blockquote: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n codeBlock: false,\n horizontalRule: false,\n }),\n Placeholder.configure({\n placeholder: \"Click to edit...\",\n }),\n ],\n content: element.textContent ?? \"\",\n editorProps: {\n attributes: {\n class: \"upstart-editor-active\",\n style: \"outline: 2px solid #3b82f6; outline-offset: 2px;\",\n },\n },\n onUpdate: ({ editor }) => {\n debouncedSave(hash, editor.getText(), options.autoSaveDelay);\n },\n onBlur: ({ editor }) => {\n saveText(hash, editor.getText());\n destroyEditor(hash);\n },\n onCreate: ({ editor }) => {\n editor.commands.focus(\"end\");\n },\n });\n}\n\nfunction createRichTextEditor(\n element: HTMLElement,\n hash: string,\n options: Required<UpstartEditorOptions>,\n): Editor {\n const bubbleMenuElement = createBubbleMenuElement();\n const extensions: Extension[] = [\n StarterKit,\n Placeholder.configure({\n placeholder: options.placeholder,\n }),\n ];\n\n if (options.bubbleMenu) {\n extensions.push(\n BubbleMenu.configure({\n element: bubbleMenuElement,\n }),\n );\n }\n\n const editor = new Editor({\n element,\n extensions,\n content: element.innerHTML,\n editorProps: {\n attributes: {\n class: \"upstart-editor-active\",\n style: \"outline: 2px solid #3b82f6; outline-offset: 2px;\",\n },\n },\n onUpdate: ({ editor: updatedEditor }) => {\n debouncedSave(hash, updatedEditor.getHTML(), options.autoSaveDelay);\n },\n onBlur: ({ editor: updatedEditor }) => {\n saveText(hash, updatedEditor.getHTML());\n destroyEditor(hash);\n },\n onCreate: ({ editor: createdEditor }) => {\n if (options.bubbleMenu) {\n wireBubbleMenu(bubbleMenuElement, createdEditor);\n }\n createdEditor.commands.focus(\"end\");\n },\n });\n\n return editor;\n}\n\nfunction shouldUseRichText(element: HTMLElement, options: Required<UpstartEditorOptions>): boolean {\n const tagName = element.tagName.toLowerCase();\n\n if (options.plainTextElements.includes(tagName)) {\n return false;\n }\n\n if (options.richTextElements.includes(tagName)) {\n return true;\n }\n\n return true;\n}\n\nfunction debouncedSave(hash: string, content: string, delay: number): void {\n const existingTimeout = saveTimeouts.get(hash);\n if (existingTimeout) {\n clearTimeout(existingTimeout);\n }\n\n const timeoutId = window.setTimeout(() => {\n sendToParent({\n type: \"text-update\",\n hash,\n newText: content,\n });\n }, delay);\n\n saveTimeouts.set(hash, timeoutId);\n}\n\nfunction saveText(hash: string, newText: string): void {\n try {\n sendToParent({\n type: \"text-save\",\n hash,\n newText,\n });\n\n console.log(\"[Upstart Editor] Text save message sent:\", hash);\n } catch (error) {\n console.error(\"[Upstart Editor] Failed to send save message:\", error);\n sendToParent({\n type: \"editor-error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n}\n\nfunction destroyEditor(hash: string): void {\n const instance = activeEditors.get(hash);\n if (!instance) {\n return;\n }\n\n instance.editor.destroy();\n restoreStyles(instance.element);\n activeEditors.delete(hash);\n\n const existingTimeout = saveTimeouts.get(hash);\n if (existingTimeout) {\n clearTimeout(existingTimeout);\n saveTimeouts.delete(hash);\n }\n}\n\nfunction registerKeyboardShortcuts(): void {\n if (shortcutsRegistered) {\n return;\n }\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\") {\n blurAllEditors();\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Enter\") {\n blurAllEditors();\n }\n });\n\n shortcutsRegistered = true;\n}\n\nfunction blurAllEditors(): void {\n activeEditors.forEach((instance) => {\n instance.editor.commands.blur();\n });\n}\n\nfunction getEditableHash(element: HTMLElement): string | null {\n return element.dataset.upstartHash ?? null;\n}\n\nfunction cacheStyles(element: HTMLElement): void {\n if (styleCache.has(element)) {\n return;\n }\n\n styleCache.set(element, {\n outline: element.style.outline || \"\",\n outlineOffset: element.style.outlineOffset || \"\",\n cursor: element.style.cursor || \"\",\n transition: element.style.transition || \"\",\n });\n}\n\nfunction applyHoverStyles(element: HTMLElement): void {\n cacheStyles(element);\n element.style.outline = \"1px dashed #3b82f6\";\n element.style.outlineOffset = \"2px\";\n element.style.cursor = \"text\";\n}\n\nfunction applyActiveStyles(element: HTMLElement): void {\n cacheStyles(element);\n element.style.outline = \"2px solid #3b82f6\";\n element.style.outlineOffset = \"2px\";\n element.style.cursor = \"text\";\n}\n\nfunction restoreStyles(element: HTMLElement): void {\n const cached = styleCache.get(element);\n if (!cached) {\n element.style.outline = \"\";\n element.style.outlineOffset = \"\";\n element.style.cursor = \"\";\n element.style.transition = \"\";\n return;\n }\n\n element.style.outline = cached.outline;\n element.style.outlineOffset = cached.outlineOffset;\n element.style.cursor = cached.cursor;\n element.style.transition = cached.transition;\n}\n\nfunction createBubbleMenuElement(): HTMLDivElement {\n const menu = document.createElement(\"div\");\n menu.className = \"upstart-editor-bubble-menu\";\n menu.style.cssText =\n \"display: flex; gap: 6px; padding: 6px 8px; background: #111827; color: #ffffff; \" +\n \"border-radius: 6px; font-size: 12px; box-shadow: 0 6px 16px rgba(0,0,0,0.2);\";\n\n const buttons = [\n { label: \"B\", command: \"bold\" },\n { label: \"I\", command: \"italic\" },\n { label: \"S\", command: \"strike\" },\n ];\n\n for (const { label, command } of buttons) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = label;\n button.dataset.command = command;\n button.style.cssText =\n \"background: transparent; border: none; color: inherit; cursor: pointer; font-weight: 600;\";\n menu.appendChild(button);\n }\n\n return menu;\n}\n\nfunction wireBubbleMenu(menu: HTMLDivElement, editor: Editor): void {\n menu.addEventListener(\"mousedown\", (event) => {\n event.preventDefault();\n });\n\n menu.addEventListener(\"click\", (event) => {\n const target = event.target as HTMLElement | null;\n const command = target?.dataset.command;\n\n if (!command) {\n return;\n }\n\n const chain = editor.chain().focus();\n\n if (command === \"bold\") {\n chain.toggleBold().run();\n }\n\n if (command === \"italic\") {\n chain.toggleItalic().run();\n }\n\n if (command === \"strike\") {\n chain.toggleStrike().run();\n }\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"text-editor.js","names":["DEFAULT_OPTIONS: Required<UpstartEditorOptions>","resolvedOptions: Required<UpstartEditorOptions>","domObserver: MutationObserver | null","reactivateTimer: number | null","timer: number | null","editor: Editor","extensions: Extension[]","extensions: (Extension | ReturnType<typeof Node.create>)[]","BUBBLE_MENU_GROUPS: { command: string; icon: string; title: string }[][]"],"sources":["../../../src/vite-plugin-upstart-editor/runtime/text-editor.ts"],"sourcesContent":["import { Editor, Extension, Node } from \"@tiptap/core\";\nimport { BubbleMenu } from \"@tiptap/extension-bubble-menu\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport { sendToParent } from \"./utils.js\";\nimport type { EditorInstance, TextEditorMode, UpstartEditorOptions } from \"./types.js\";\n\n/**\n * Custom Document node for inline elements (e.g. <a>, <span>, headings).\n * Uses `inline*` content instead of the default `block+` to prevent\n * TipTap from wrapping text in <p> tags inside inline elements.\n */\nconst InlineDocument = Node.create({\n name: \"doc\",\n topNode: true,\n content: \"inline*\",\n});\n\n/**\n * Remaps Enter to insert a <br> (hard break) instead of creating a new paragraph.\n * Used in inline-rich mode where block nodes are not allowed.\n */\nconst EnterHardBreak = Extension.create({\n name: \"enterHardBreak\",\n addKeyboardShortcuts() {\n return {\n Enter: () => this.editor.commands.setHardBreak(),\n };\n },\n});\n\nconst DEFAULT_OPTIONS: Required<UpstartEditorOptions> = {\n richTextElements: [\"p\", \"div\", \"article\", \"section\"],\n inlineRichTextElements: [\"a\", \"span\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"],\n plainTextElements: [\"button\", \"label\"],\n bubbleMenu: true,\n placeholder: \"Start typing...\",\n autoSaveDelay: 1000,\n};\n\nconst activeEditors = new Map<string, EditorInstance>();\nlet i18nSyncInProgress = false;\nconst styleCache = new WeakMap<\n HTMLElement,\n { outline: string; outlineOffset: string; cursor: string; transition: string }\n>();\nlet resolvedOptions: Required<UpstartEditorOptions> = DEFAULT_OPTIONS;\nlet shortcutsRegistered = false;\nlet domObserver: MutationObserver | null = null;\nlet reactivateTimer: number | null = null;\n\n/**\n * Initialize TipTap text editing for elements marked as editable.\n * Activation is deferred to avoid conflicting with React hydration.\n */\nexport function initTextEditor(options: UpstartEditorOptions = {}): void {\n if (typeof window === \"undefined\") {\n console.warn(\"[Upstart Editor] Cannot initialize text editor: not running in a browser environment\");\n return;\n }\n\n resolvedOptions = { ...DEFAULT_OPTIONS, ...options };\n registerKeyboardShortcuts();\n\n // Defer activation to let React finish hydrating the server-rendered HTML.\n waitForHydration(() => {\n injectEditorStyles();\n // activateAllEditors();\n startDomObserver();\n });\n}\n\nfunction waitForHydration(callback: () => void): void {\n // Remix/React 18 wraps hydrateRoot in startTransition, making hydration a\n // concurrent (low-priority) operation that can span many frames after the\n // load event. Instead of guessing a delay, we wait for the DOM to stabilise:\n // once 200 ms pass without any childList mutations, hydration is done.\n const STABILITY_MS = 200;\n\n const onReady = () => {\n let timer: number | null = null;\n\n const settle = () => {\n if (timer) clearTimeout(timer);\n timer = window.setTimeout(() => {\n observer.disconnect();\n callback();\n }, STABILITY_MS);\n };\n\n const observer = new MutationObserver(settle);\n observer.observe(document.documentElement, { childList: true, subtree: true });\n\n // Kick off the first timer (covers case where no mutations occur after load)\n settle();\n };\n\n if (document.readyState === \"complete\") {\n onReady();\n } else {\n window.addEventListener(\"load\", onReady, { once: true });\n }\n}\n\n/**\n * Inject CSS rules that visually hide original content when an editor is active.\n * This avoids moving DOM nodes (which breaks React hydration).\n *\n * - `font-size: 0` + `color: transparent` hides direct text nodes\n * - `> *:not(.ProseMirror)` hides child elements\n * - ProseMirror gets explicit inline styles to restore text rendering\n */\nfunction injectEditorStyles(): void {\n if (document.getElementById(\"upstart-editor-styles\")) return;\n\n const style = document.createElement(\"style\");\n style.id = \"upstart-editor-styles\";\n style.textContent = [\n \"[data-upstart-editor-active] {\",\n \" cursor: text;\",\n \" transition: outline 100ms;\",\n \"}\",\n \"[data-upstart-editor-active]:hover {\",\n \" outline: 1px solid #7270c6;\",\n \" outline-offset: 4px;\",\n \"}\",\n // \"[data-upstart-editor-active] > *:not(.ProseMirror) {\",\n // \" display: none !important;\",\n // \"}\",\n \"[data-upstart-editor-active] .ProseMirror {\",\n \" outline: none !important;\",\n \" font-size: inherit !important;\",\n \" line-height: inherit !important;\",\n \" color: inherit !important;\",\n \" letter-spacing: inherit !important;\",\n \" font-weight: inherit !important;\",\n \" white-space: inherit !important;\",\n \"}\",\n \"[data-upstart-editor-active] .ProseMirror:focus {\",\n \" outline: none !important;\",\n \"}\",\n ].join(\"\\n\");\n document.head.appendChild(style);\n}\n\n/**\n * Activate editors on all editable elements. Safe to call multiple times.\n */\nexport function activateAllEditors(): void {\n try {\n cleanupOrphanedEditors();\n const editables = document.querySelectorAll<HTMLElement>('[data-upstart-editable-text=\"true\"]');\n editables.forEach((element) => setupEditableElement(element, resolvedOptions));\n console.log(\"[Upstart Editor] Text editors activated\");\n } catch (error) {\n console.error(\"[Upstart Editor] Failed to activate text editors:\", error);\n sendToParent({\n type: \"editor-error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n}\n\n/**\n * Destroy all active editors.\n */\nexport function destroyAllActiveEditors(): void {\n stopDomObserver();\n for (const hash of activeEditors.keys()) {\n destroyEditor(hash);\n }\n}\n\nfunction setupEditableElement(element: HTMLElement, options: Required<UpstartEditorOptions>): void {\n const hash = getEditableHash(element);\n if (!hash || activeEditors.has(hash)) {\n return;\n }\n\n cacheStyles(element);\n activateEditor(element, hash, options);\n}\n\nfunction activateEditor(element: HTMLElement, hash: string, options: Required<UpstartEditorOptions>): void {\n const mode = getEditorMode(element, options);\n\n let editor: Editor;\n switch (mode) {\n case \"block-rich\":\n editor = createRichTextEditor(element, hash, options);\n break;\n case \"inline-rich\":\n editor = createInlineRichTextEditor(element, hash, options);\n break;\n case \"plain\":\n editor = createPlainTextEditor(element, hash, options);\n break;\n }\n\n // Restore text rendering on ProseMirror (overrides inherited font-size: 0 etc.)\n\n // Mark element — triggers CSS rules that hide original content\n element.dataset.upstartEditorActive = \"true\";\n\n applyActiveStyles(element);\n activeEditors.set(hash, { editor, element, hash, mode });\n}\n\nfunction createPlainTextEditor(\n element: HTMLElement,\n hash: string,\n options: Required<UpstartEditorOptions>,\n): Editor {\n const content = element.textContent ?? \"\";\n let hasChanged = false;\n\n const editor = new Editor({\n element,\n extensions: [\n InlineDocument,\n StarterKit.configure({\n document: false,\n heading: false,\n bold: false,\n italic: false,\n strike: false,\n blockquote: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n codeBlock: false,\n horizontalRule: false,\n }),\n Placeholder.configure({\n placeholder: \"Click to edit...\",\n }),\n ],\n content,\n editorProps: {\n attributes: {\n class: \"upstart-editor-active\",\n },\n },\n onUpdate: ({ editor: e }) => {\n if (i18nSyncInProgress) return;\n hasChanged = true;\n // const content = e.getText();\n // debouncedSave(hash, content, options.autoSaveDelay);\n syncI18nSiblings(hash);\n },\n onBlur: ({ editor: e }) => {\n if (!hasChanged) return;\n hasChanged = false;\n saveText(hash, e.getText());\n },\n });\n\n return editor;\n}\n\nfunction createRichTextEditor(\n element: HTMLElement,\n hash: string,\n options: Required<UpstartEditorOptions>,\n): Editor {\n const content = element.innerHTML;\n element.innerHTML = \"\"; // Clear the element first!\n let hasChanged = false;\n\n const bubbleMenuElement = createBubbleMenuElement();\n const extensions: Extension[] = [\n StarterKit,\n Placeholder.configure({\n placeholder: options.placeholder,\n }),\n ];\n\n if (options.bubbleMenu) {\n extensions.push(\n BubbleMenu.configure({\n element: bubbleMenuElement,\n }),\n );\n }\n\n const editor = new Editor({\n element,\n extensions,\n content,\n editorProps: {\n attributes: {\n class: \"upstart-editor-active\",\n },\n },\n onUpdate: ({ editor: e }) => {\n if (i18nSyncInProgress) return;\n hasChanged = true;\n // const content = e.getHTML();\n // debouncedSave(hash, content, options.autoSaveDelay);\n syncI18nSiblings(hash);\n },\n onBlur: ({ editor: e }) => {\n if (!hasChanged) return;\n hasChanged = false;\n saveText(hash, e.getHTML());\n },\n });\n\n if (options.bubbleMenu) {\n wireBubbleMenu(bubbleMenuElement, editor);\n }\n\n return editor;\n}\n\nfunction createInlineRichTextEditor(\n element: HTMLElement,\n hash: string,\n options: Required<UpstartEditorOptions>,\n): Editor {\n const content = element.innerHTML;\n element.innerHTML = \"\"; // Clear the element first!\n let hasChanged = false;\n\n const bubbleMenuElement = createBubbleMenuElement(\"inline\");\n const extensions: (Extension | ReturnType<typeof Node.create>)[] = [\n InlineDocument,\n EnterHardBreak,\n StarterKit.configure({\n document: false,\n heading: false,\n blockquote: false,\n bulletList: false,\n orderedList: false,\n listItem: false,\n codeBlock: false,\n horizontalRule: false,\n }),\n Placeholder.configure({\n placeholder: \"Click to edit...\",\n }),\n ];\n\n if (options.bubbleMenu) {\n extensions.push(\n BubbleMenu.configure({\n element: bubbleMenuElement,\n }),\n );\n }\n\n const editor = new Editor({\n element,\n extensions,\n content,\n editorProps: {\n attributes: {\n class: \"upstart-editor-active\",\n },\n },\n onUpdate: ({ editor: e }) => {\n if (i18nSyncInProgress) return;\n hasChanged = true;\n // const content = e.getHTML();\n // debouncedSave(hash, content, options.autoSaveDelay);\n syncI18nSiblings(hash);\n },\n onBlur: ({ editor: e }) => {\n if (!hasChanged) return;\n hasChanged = false;\n saveText(hash, e.getHTML());\n },\n });\n\n if (options.bubbleMenu) {\n wireBubbleMenu(bubbleMenuElement, editor);\n }\n\n return editor;\n}\n\nfunction getEditorMode(element: HTMLElement, options: Required<UpstartEditorOptions>): TextEditorMode {\n const tagName = element.tagName.toLowerCase();\n\n if (options.plainTextElements.includes(tagName)) {\n return \"plain\";\n }\n\n if (options.inlineRichTextElements.includes(tagName)) {\n return \"inline-rich\";\n }\n\n if (options.richTextElements.includes(tagName)) {\n return \"block-rich\";\n }\n\n return \"block-rich\";\n}\n\nfunction syncI18nSiblings(sourceHash: string): void {\n console.log(\"[Upstart Editor] Syncing i18n siblings for\", sourceHash);\n const instance = activeEditors.get(sourceHash);\n if (!instance) {\n console.warn(\"[Upstart Editor] No editor instance found for hash:\", sourceHash);\n return;\n }\n\n const i18nKey = instance.element.dataset.upstartI18n;\n if (!i18nKey) {\n console.warn(\"[Upstart Editor] No sibling i18n key found for element:\", instance.element);\n return;\n }\n\n const siblings = document.querySelectorAll<HTMLElement>(`[data-upstart-i18n=\"${CSS.escape(i18nKey)}\"]`);\n console.log(`[Upstart Editor] Found ${siblings.length} sibling(s) with i18n key \"${i18nKey}\"`);\n\n // Always use plain text so each sibling's schema can wrap it correctly\n // (e.g. InlineDocument vs block Document have incompatible content rules).\n const plainContent = instance.editor.getText();\n\n i18nSyncInProgress = true;\n try {\n for (const sibling of siblings) {\n if (sibling === instance.element) continue;\n\n const siblingHash = sibling.dataset.upstartHash;\n const siblingInstance = siblingHash ? activeEditors.get(siblingHash) : null;\n\n if (siblingInstance) {\n console.log(\n `[Upstart Editor] Updating sibling editor (hash: ${siblingHash}) with new content`,\n siblingInstance,\n );\n sibling.innerText = plainContent;\n siblingInstance.editor.chain().selectAll().insertContent(plainContent).run();\n } else {\n sibling.textContent = plainContent;\n }\n }\n } finally {\n i18nSyncInProgress = false;\n }\n}\n\nfunction saveText(hash: string, newText: string): void {\n try {\n const instance = activeEditors.get(hash);\n const dataset = instance?.element.dataset ?? {};\n const [namespace, key] = dataset.upstartI18n?.split(\":\") ?? [];\n sendToParent({\n type: \"text-edit\",\n payload: {\n action: \"editText\",\n content: newText,\n namespace,\n key,\n language: document.documentElement.lang,\n },\n });\n\n console.log(\"[Upstart Editor] Text save message sent:\", hash);\n } catch (error) {\n console.error(\"[Upstart Editor] Failed to send save message:\", error);\n sendToParent({\n type: \"editor-error\",\n error: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n}\n\nfunction destroyEditor(hash: string): void {\n const instance = activeEditors.get(hash);\n if (!instance) {\n return;\n }\n\n const finalContent = instance.mode === \"plain\" ? instance.editor.getText() : instance.editor.getHTML();\n\n instance.editor.destroy();\n\n // Remove ProseMirror DOM\n const editorDom = instance.element.querySelector(\".ProseMirror\");\n if (editorDom) editorDom.remove();\n\n // Remove CSS-hiding marker — original content becomes visible again\n delete instance.element.dataset.upstartEditorActive;\n\n // Update element content with the final edited text\n if (instance.mode === \"plain\") {\n instance.element.textContent = finalContent;\n } else {\n instance.element.innerHTML = finalContent;\n }\n\n restoreStyles(instance.element);\n activeEditors.delete(hash);\n}\n\n// ---------------------------------------------------------------------------\n// MutationObserver — re-activates editors after React re-renders\n// ---------------------------------------------------------------------------\n\nfunction startDomObserver(): void {\n if (domObserver) return;\n\n domObserver = new MutationObserver((mutations) => {\n let needsReactivation = false;\n\n for (const mutation of mutations) {\n if (mutation.type !== \"childList\") continue;\n\n for (const node of mutation.addedNodes) {\n if (\n node instanceof HTMLElement &&\n (node.matches?.('[data-upstart-editable-text=\"true\"]') ||\n node.querySelector?.('[data-upstart-editable-text=\"true\"]'))\n ) {\n needsReactivation = true;\n break;\n }\n }\n\n if (!needsReactivation) {\n for (const node of mutation.removedNodes) {\n if (\n node instanceof HTMLElement &&\n (node.matches?.('[data-upstart-editable-text=\"true\"]') ||\n node.querySelector?.('[data-upstart-editable-text=\"true\"]'))\n ) {\n needsReactivation = true;\n break;\n }\n }\n }\n\n if (needsReactivation) break;\n }\n\n if (needsReactivation) {\n scheduleReactivation();\n }\n });\n\n domObserver.observe(document.body, { childList: true, subtree: true });\n}\n\nfunction stopDomObserver(): void {\n if (domObserver) {\n domObserver.disconnect();\n domObserver = null;\n }\n if (reactivateTimer) {\n clearTimeout(reactivateTimer);\n reactivateTimer = null;\n }\n}\n\nfunction scheduleReactivation(): void {\n if (reactivateTimer) clearTimeout(reactivateTimer);\n reactivateTimer = window.setTimeout(() => {\n reactivateTimer = null;\n activateAllEditors();\n }, 50);\n}\n\n/**\n * Remove editors whose host element has been detached from the document\n * (e.g. React replaced the subtree during a re-render).\n */\nfunction cleanupOrphanedEditors(): void {\n for (const [hash, instance] of activeEditors) {\n if (!document.contains(instance.element)) {\n instance.editor.destroy();\n activeEditors.delete(hash);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Keyboard shortcuts\n// ---------------------------------------------------------------------------\n\nfunction registerKeyboardShortcuts(): void {\n if (shortcutsRegistered) {\n return;\n }\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\") {\n blurAllEditors();\n }\n\n if ((event.metaKey || event.ctrlKey) && event.key === \"Enter\") {\n blurAllEditors();\n }\n });\n\n shortcutsRegistered = true;\n}\n\nfunction blurAllEditors(): void {\n activeEditors.forEach((instance) => {\n instance.editor.commands.blur();\n });\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction getEditableHash(element: HTMLElement): string | null {\n return element.dataset.upstartHash ?? null;\n}\n\nfunction cacheStyles(element: HTMLElement): void {\n if (styleCache.has(element)) {\n return;\n }\n\n styleCache.set(element, {\n outline: element.style.outline || \"\",\n outlineOffset: element.style.outlineOffset || \"\",\n cursor: element.style.cursor || \"\",\n transition: element.style.transition || \"\",\n });\n}\n\nfunction applyActiveStyles(element: HTMLElement): void {\n cacheStyles(element);\n}\n\nfunction restoreStyles(element: HTMLElement): void {\n const cached = styleCache.get(element);\n if (!cached) {\n element.style.outline = \"\";\n element.style.outlineOffset = \"\";\n element.style.cursor = \"\";\n element.style.transition = \"\";\n return;\n }\n\n element.style.outline = cached.outline;\n element.style.outlineOffset = cached.outlineOffset;\n element.style.cursor = cached.cursor;\n element.style.transition = cached.transition;\n}\n\nconst BUBBLE_MENU_GROUPS: { command: string; icon: string; title: string }[][] = [\n [\n { command: \"bold\", icon: \"format-bold\", title: \"Bold\" },\n { command: \"italic\", icon: \"format-italic\", title: \"Italic\" },\n { command: \"strike\", icon: \"format-strikethrough\", title: \"Strikethrough\" },\n { command: \"code\", icon: \"code-tags\", title: \"Inline Code\" },\n ],\n [\n { command: \"heading\", icon: \"format-header-1\", title: \"Heading\" },\n { command: \"blockquote\", icon: \"format-quote-close\", title: \"Blockquote\" },\n ],\n [\n { command: \"bulletList\", icon: \"format-list-bulleted\", title: \"Bullet List\" },\n { command: \"orderedList\", icon: \"format-list-numbered\", title: \"Ordered List\" },\n ],\n];\n\nfunction getIconifyUrl(iconName: string): string {\n return `https://api.iconify.design/mdi/${iconName}.svg?height=none&color=%23fff`;\n}\n\nfunction createBubbleMenuElement(mode: \"block\" | \"inline\" = \"block\"): HTMLDivElement {\n const groups = mode === \"inline\" ? [BUBBLE_MENU_GROUPS[0]] : BUBBLE_MENU_GROUPS;\n const menu = document.createElement(\"div\");\n menu.className = \"upstart-editor-bubble-menu\";\n menu.style.cssText =\n \"display: flex; align-items: center; gap: 2px; padding: 4px; \" +\n \"background: #111827; color: #ffffff; border-radius: 8px; \" +\n \"font-size: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.25);\";\n\n groups.forEach((group, groupIndex) => {\n if (groupIndex > 0) {\n const separator = document.createElement(\"div\");\n separator.style.cssText =\n \"width: 1px; height: 16px; background: rgba(255,255,255,0.2); \" + \"margin: 0 4px; flex-shrink: 0;\";\n menu.appendChild(separator);\n }\n\n for (const { command, icon, title } of group) {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.dataset.command = command;\n button.title = title;\n button.style.cssText =\n \"background: transparent; border: none; color: inherit; cursor: pointer; \" +\n \"display: flex; align-items: center; justify-content: center; \" +\n \"width: 28px; height: 28px; padding: 4px; border-radius: 4px; \" +\n \"transition: background 0.15s ease;\";\n\n const img = document.createElement(\"img\");\n img.src = getIconifyUrl(icon);\n img.alt = title;\n img.style.cssText = \"width: 18px; height: 18px; display: block; pointer-events: none;\";\n button.appendChild(img);\n\n button.addEventListener(\"mouseenter\", () => {\n if (!button.dataset.active) {\n button.style.background = \"rgba(255,255,255,0.12)\";\n }\n });\n button.addEventListener(\"mouseleave\", () => {\n button.style.background = button.dataset.active ? \"rgba(255,255,255,0.2)\" : \"transparent\";\n });\n\n menu.appendChild(button);\n }\n });\n\n return menu;\n}\n\nfunction wireBubbleMenu(menu: HTMLDivElement, editor: Editor): void {\n menu.addEventListener(\"mousedown\", (event) => {\n event.preventDefault();\n });\n\n menu.addEventListener(\"click\", (event) => {\n const target = event.target as HTMLElement | null;\n const command = target?.dataset.command;\n if (!command) return;\n\n const chain = editor.chain().focus();\n\n switch (command) {\n case \"bold\":\n chain.toggleBold().run();\n break;\n case \"italic\":\n chain.toggleItalic().run();\n break;\n case \"strike\":\n chain.toggleStrike().run();\n break;\n case \"code\":\n chain.toggleCode().run();\n break;\n case \"heading\":\n chain.toggleHeading({ level: 1 }).run();\n break;\n case \"blockquote\":\n chain.toggleBlockquote().run();\n break;\n case \"bulletList\":\n chain.toggleBulletList().run();\n break;\n case \"orderedList\":\n chain.toggleOrderedList().run();\n break;\n }\n });\n\n const updateActiveStates = (): void => {\n const buttons = menu.querySelectorAll<HTMLButtonElement>(\"button[data-command]\");\n for (const button of buttons) {\n const command = button.dataset.command!;\n const isActive =\n command === \"heading\" ? editor.isActive(\"heading\", { level: 1 }) : editor.isActive(command);\n\n if (isActive) {\n button.dataset.active = \"true\";\n button.style.background = \"rgba(255,255,255,0.2)\";\n } else {\n delete button.dataset.active;\n button.style.background = \"transparent\";\n }\n }\n };\n\n editor.on(\"transaction\", updateActiveStates);\n updateActiveStates();\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { PayloadEditText } from "../../upstart-editor-api.js";
1
2
  import { Editor } from "@tiptap/core";
2
3
 
3
4
  //#region src/vite-plugin-upstart-editor/runtime/types.d.ts
@@ -6,6 +7,10 @@ import { Editor } from "@tiptap/core";
6
7
  * Editor mode
7
8
  */
8
9
  type EditorMode = "preview" | "edit";
10
+ /**
11
+ * Text editor mode: determines schema constraints and bubble menu options.
12
+ */
13
+ type TextEditorMode = "block-rich" | "inline-rich" | "plain";
9
14
  /**
10
15
  * Element bounds used for UI positioning.
11
16
  */
@@ -24,18 +29,14 @@ interface EditorInstance {
24
29
  editor: Editor;
25
30
  element: HTMLElement;
26
31
  hash: string;
32
+ mode: TextEditorMode;
27
33
  }
28
34
  /**
29
35
  * Messages sent from iframe to parent editor.
30
36
  */
31
37
  type EditorMessage = {
32
- type: "text-update";
33
- hash: string;
34
- newText: string;
35
- } | {
36
- type: "text-save";
37
- hash: string;
38
- newText: string;
38
+ type: "text-edit";
39
+ payload: PayloadEditText;
39
40
  } | {
40
41
  type: "editor-ready";
41
42
  } | {
@@ -48,9 +49,10 @@ type EditorMessage = {
48
49
  } | {
49
50
  type: "element-clicked";
50
51
  hash: string;
51
- componentName: string;
52
+ componentName?: string;
52
53
  filePath: string;
53
54
  currentClassName: string;
55
+ classNameId: string;
54
56
  bounds: ElementBounds;
55
57
  };
56
58
  /**
@@ -85,9 +87,15 @@ interface UpstartEditorOptions {
85
87
  * @default ['p', 'div', 'article', 'section']
86
88
  */
87
89
  richTextElements?: string[];
90
+ /**
91
+ * Elements that should use inline rich text editing (inline formatting only, no blocks).
92
+ * Uses a custom inline document schema to prevent block elements like <p> inside inline elements.
93
+ * @default ['a', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
94
+ */
95
+ inlineRichTextElements?: string[];
88
96
  /**
89
97
  * Elements that should use plain text editing (no formatting).
90
- * @default ['button', 'a', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'label']
98
+ * @default ['button', 'label']
91
99
  */
92
100
  plainTextElements?: string[];
93
101
  /**
@@ -122,5 +130,5 @@ interface UpstartEditorPluginOptions {
122
130
  autoInject?: boolean;
123
131
  }
124
132
  //#endregion
125
- export { EditorInstance, EditorMessage, EditorMode, ElementBounds, ParentMessage, UpstartEditorMessage, UpstartEditorOptions, UpstartEditorPluginOptions, UpstartParentMessage };
133
+ export { EditorInstance, EditorMessage, EditorMode, ElementBounds, ParentMessage, TextEditorMode, UpstartEditorMessage, UpstartEditorOptions, UpstartEditorPluginOptions, UpstartParentMessage };
126
134
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/vite-plugin-upstart-editor/runtime/types.ts"],"sourcesContent":[],"mappings":";;;;;;AAKA;AAKiB,KALL,UAAA,GAKkB,SAAA,GAAA,MAAA;AAY9B;AASA;AAkBA;AAKiB,UA5CA,aAAA,CA4CoB;EASpB,GAAA,EAAA,MAAA;EASA,IAAA,EAAA,MAAA;EAmCA,KAAA,EAAA,MAAA;;;;;;;;UArFA,cAAA;UACP;WACC;;;;;;KAOC,aAAA;;;;;;;;;;;;;;;;UAKyC;;;;;;;UAOvC;;;;;KAMF,aAAA;;QAA0C;;;;;UAKrC,oBAAA;;QAET;;;;;;UAOS,oBAAA;;QAET;;;;;;UAOS,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAmCA,0BAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/vite-plugin-upstart-editor/runtime/types.ts"],"sourcesContent":[],"mappings":";;;;;;;AAMA;AAKY,KALA,UAAA,GAKc,SAAA,GAAA,MAAA;AAK1B;AAYA;;AAEW,KAnBC,cAAA,GAmBD,YAAA,GAAA,aAAA,GAAA,OAAA;;;AAQX;AACkC,UAvBjB,aAAA,CAuBiB;EAGmB,GAAA,EAAA,MAAA;EAQvC,IAAA,EAAA,MAAA;EAAa,KAAA,EAAA,MAAA;EAMf,MAAA,EAAA,MAAA;EAKK,KAAA,EAAA,MAAA;EASA,MAAA,EAAA,MAAA;AASjB;AA0CA;;;UA7FiB,cAAA;UACP;WACC;;QAEH;;;;;KAMI,aAAA;;WACsB;;;;;;;;;UAGmB;;;;;;;;UAQvC;;;;;KAMF,aAAA;;QAA0C;;;;;UAKrC,oBAAA;;QAET;;;;;;UAOS,oBAAA;;QAET;;;;;;UAOS,oBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA0CA,0BAAA"}
@@ -1,4 +1,4 @@
1
- import * as unplugin0 from "unplugin";
1
+ import * as unplugin2 from "unplugin";
2
2
  import { Theme } from "@upstart.gg/sdk/themes/theme";
3
3
 
4
4
  //#region src/vite-plugin-upstart-theme.d.ts
@@ -15,8 +15,8 @@ interface PluginOptions {
15
15
  /**
16
16
  * Unplugin-based theme generator
17
17
  */
18
- declare const upstartTheme: unplugin0.UnpluginInstance<PluginOptions, boolean>;
19
- declare const _default: (options: PluginOptions) => unplugin0.VitePlugin<any> | unplugin0.VitePlugin<any>[];
18
+ declare const upstartTheme: unplugin2.UnpluginInstance<PluginOptions, boolean>;
19
+ declare const _default: (options: PluginOptions) => unplugin2.VitePlugin<any> | unplugin2.VitePlugin<any>[];
20
20
  //#endregion
21
21
  export { _default as default, upstartTheme };
22
22
  //# sourceMappingURL=vite-plugin-upstart-theme.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-upstart-theme.d.ts","names":[],"sources":["../src/vite-plugin-upstart-theme.ts"],"sourcesContent":[],"mappings":";;;;UAWU,aAAA;;WAEC;IAFD,IAAA,CAAA,EAGC,KAHY;IA2OV,OAAA,EAAA,OAiEX,GAAA,MAjEuB;EAiEtB,CAAA;;;;;;;;cAjEU,cAAY,SAAA,CAAA,iBAAA;cAiEtB"}
1
+ {"version":3,"file":"vite-plugin-upstart-theme.d.ts","names":[],"sources":["../src/vite-plugin-upstart-theme.ts"],"sourcesContent":[],"mappings":";;;;UAWU,aAAA;;WAEC;IAFD,IAAA,CAAA,EAGC,KAHY;IA2OV,OAAA,EAAA,OA8DX,GAAA,MA9DuB;EA8DtB,CAAA;;;;;;;;cA9DU,cAAY,SAAA,CAAA,iBAAA;cA8DtB"}
@@ -1,5 +1,5 @@
1
- import { createUnplugin } from "unplugin";
2
1
  import path from "node:path";
2
+ import { createUnplugin } from "unplugin";
3
3
  import { fontStacksFonts, processTheme } from "@upstart.gg/sdk/themes/theme";
4
4
  import fs from "node:fs";
5
5
 
@@ -148,7 +148,6 @@ const upstartTheme = createUnplugin((opts) => {
148
148
  const fontsCSS = generateFontsCSS(themes.light, themes.dark, fontsDisplay);
149
149
  const fontsCSSPath = path.join(outputDir, "fonts.css");
150
150
  fs.writeFileSync(fontsCSSPath, fontsCSS);
151
- console.log(`✓ Generated fonts CSS: ${fontsCSSPath}`);
152
151
  const output = [];
153
152
  output.push(generateThemeBlock(themes.light, themes.dark));
154
153
  output.push("");
@@ -168,7 +167,6 @@ const upstartTheme = createUnplugin((opts) => {
168
167
  }
169
168
  const cssContent = output.join("\n");
170
169
  fs.writeFileSync(opts.outputPath, cssContent);
171
- console.log(`✓ Generated theme CSS: ${opts.outputPath}`);
172
170
  } }
173
171
  };
174
172
  });
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-upstart-theme.js","names":["googleFonts: Array<GoogleFont>","lines: string[]","output: string[]"],"sources":["../src/vite-plugin-upstart-theme.ts"],"sourcesContent":["import { createUnplugin } from \"unplugin\";\nimport {\n GenericFont,\n GoogleFont,\n type Theme,\n fontStacksFonts,\n processTheme,\n} from \"@upstart.gg/sdk/themes/theme\";\nimport fs from \"fs\";\nimport path from \"path\";\n\ninterface PluginOptions {\n themes: {\n light: Theme;\n dark?: Theme;\n default: \"light\" | \"dark\";\n };\n outputPath: string;\n /** Google Fonts display parameter (default: 'swap') */\n fontsDisplay?: \"auto\" | \"block\" | \"swap\" | \"fallback\" | \"optional\";\n}\n\n/**\n * Collects Google Fonts from a theme's typography configuration\n */\nfunction collectGoogleFonts(theme: Theme) {\n const { typography } = theme;\n if (!typography) return [];\n\n const googleFonts: Array<GoogleFont> = [];\n const seen = new Set<string>();\n\n const addFont = (font?: GenericFont) => {\n if (font?.type === \"google\" && !seen.has(font.family)) {\n seen.add(font.family);\n googleFonts.push(font);\n }\n };\n\n addFont(typography.sans);\n addFont(typography.serif);\n if (typography.others) {\n Object.values(typography.others).forEach(addFont);\n }\n\n return googleFonts;\n}\n\n/**\n * Generates the fonts.css file content with Google Fonts imports\n */\nfunction generateFontsCSS(\n lightTheme: Theme,\n darkTheme: Theme | null = null,\n display: \"auto\" | \"block\" | \"swap\" | \"fallback\" | \"optional\" = \"swap\",\n): string {\n // Collect fonts from both themes\n const allFonts = new Map<string, GoogleFont>();\n\n for (const font of collectGoogleFonts(lightTheme)) {\n allFonts.set(font.family, font);\n }\n\n if (darkTheme) {\n for (const font of collectGoogleFonts(darkTheme)) {\n allFonts.set(font.family, font);\n }\n }\n\n if (allFonts.size === 0) {\n return \"/* No Google Fonts to import */\\n\";\n }\n\n // Build the Google Fonts URL\n const families = Array.from(allFonts.values()).map((font) => {\n const name = font.family.replace(/ /g, \"+\");\n if (font.weights && font.weights.length > 1 && font.weights[0] !== font.weights.at(-1)) {\n return `family=${name}:wght@${font.weights[0]}..${font.weights.at(-1)}`;\n }\n return `family=${name}`;\n });\n\n const url = `https://fonts.googleapis.com/css2?${families.join(\"&\")}&display=${display}`;\n\n return `/* Google Fonts - Auto-generated by vite-plugin-upstart-theme */\\n@import url(\"${url}\");\\n`;\n}\n\n/**\n * Converts a font definition to a CSS font-family string\n */\nfunction fontToCss(font: Theme[\"typography\"][\"sans\"]): string {\n if (!font) return \"\";\n\n if (font.type === \"stack\") {\n return fontStacksFonts[font.family];\n }\n\n if (font.type === \"google\") {\n // For Google fonts, we just use the family name\n // The actual font loading will be handled separately\n return `\"${font.family}\", system-ui, sans-serif`;\n }\n\n return \"\";\n}\n\n/**\n * Converts camelCase to kebab-case\n */\nfunction camelToKebab(str: string): string {\n return str.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Generates @theme block with font definitions\n */\nfunction generateThemeBlock(\n lightTheme: Theme,\n darkTheme: Theme | null = null,\n defaultTheme: \"light\" | \"dark\" = \"light\",\n): string {\n const fontDefinitions = new Map<string, string>();\n\n // Process light theme fonts\n const lightTypography = lightTheme.typography;\n\n // Add sans font\n if (lightTypography.sans) {\n const fontCss = fontToCss(lightTypography.sans);\n if (fontCss) {\n fontDefinitions.set(\"sans\", fontCss);\n }\n }\n\n // Add serif font\n if (lightTypography.serif) {\n const fontCss = fontToCss(lightTypography.serif);\n if (fontCss) {\n fontDefinitions.set(\"serif\", fontCss);\n }\n }\n\n // Add other fonts\n if (lightTypography.others) {\n for (const [name, font] of Object.entries(lightTypography.others)) {\n const fontCss = fontToCss(font);\n if (fontCss) {\n fontDefinitions.set(name, fontCss);\n }\n }\n }\n\n // Process dark theme fonts if provided\n if (darkTheme) {\n const darkTypography = darkTheme.typography;\n\n if (darkTypography.sans) {\n const fontCss = fontToCss(darkTypography.sans);\n if (fontCss) {\n fontDefinitions.set(\"sans\", fontCss);\n }\n }\n\n if (darkTypography.serif) {\n const fontCss = fontToCss(darkTypography.serif);\n if (fontCss) {\n fontDefinitions.set(\"serif\", fontCss);\n }\n }\n\n if (darkTypography.others) {\n for (const [name, font] of Object.entries(darkTypography.others)) {\n const fontCss = fontToCss(font);\n if (fontCss) {\n fontDefinitions.set(name, fontCss);\n }\n }\n }\n }\n\n const fontLines = Array.from(fontDefinitions.entries())\n .map(([name, value]) => ` --font-${name}: ${value};`)\n .join(\"\\n\");\n\n return `/* Fonts in the tailwind @theme block */\n@theme {\n ${fontLines}\n}\n\n/* Exclude properties since it produce warnings and is not important */\n@plugin \"daisyui\" {\n exclude: properties;\n themes: ${lightTheme.id} ${defaultTheme === \"light\" || !darkTheme ? \"--default\" : \"\"}${darkTheme?.id && darkTheme?.id !== lightTheme.id ? `, ${darkTheme.id} ${defaultTheme === \"dark\" ? \"--default\" : \"--prefersdark\"}` : \"\"};\n logs: true;\n}\n`;\n}\n\n//\n\n/**\n * Generates @theme block for a single theme with colors and layout variables\n */\nfunction generateThemeVariables(\n theme: Theme,\n type: \"light\" | \"dark\",\n defaultTheme: \"light\" | \"dark\",\n): string {\n const processed = processTheme(theme);\n const lines: string[] = [\n ` name: \"${processed.id}\";`,\n ` color-scheme: ${processed.browserColorScheme};`,\n ...((defaultTheme === \"dark\" && theme.browserColorScheme === \"dark\") ||\n (defaultTheme === \"light\" && theme.browserColorScheme === \"light\")\n ? [` default: true;`]\n : []),\n // ...(type === \"dark\" && defaultTheme !== \"dark\" ? [` prefersdark: true;`] : [` prefersdark: false;`]),\n ];\n\n // Color variables\n for (const [colorKey, colorValue] of Object.entries(processed.colors)) {\n const kebabKey = [\"base100\", \"base200\", \"base300\"].includes(colorKey)\n ? colorKey.replace(\"base\", \"base-\")\n : camelToKebab(colorKey);\n lines.push(` --color-${kebabKey}: ${colorValue};`);\n }\n\n lines.push(\"\");\n\n // Layout variables\n lines.push(` --radius-selector: ${processed.radiusSelector};`);\n lines.push(` --radius-field: ${processed.radiusField};`);\n lines.push(` --radius-box: ${processed.radiusBox};`);\n lines.push(` --size-selector: ${processed.sizeSelector};`);\n lines.push(` --size-field: ${processed.sizeField};`);\n lines.push(` --border: ${processed.border};`);\n lines.push(` --depth: ${processed.depth ? 1 : 0};`);\n lines.push(` --noise: 0;`);\n\n // return the generated lines\n return lines.join(\"\\n\");\n}\n\n/**\n * Unplugin-based theme generator\n */\nexport const upstartTheme = createUnplugin<PluginOptions>((opts) => {\n let generated = false;\n\n return {\n name: \"unplugin-theme-generator\",\n apply: \"serve\",\n\n vite: {\n configResolved() {\n // Generate the CSS file once when config is resolved\n if (generated) return;\n generated = true;\n\n if (!opts?.themes?.light) {\n console.warn(\"No light theme provided to unplugin-theme-generator. A light theme is required.\");\n return;\n }\n\n const outputDir = path.dirname(opts.outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n const { themes, fontsDisplay = \"swap\" } = opts;\n\n // Generate fonts.css file\n const fontsCSS = generateFontsCSS(themes.light, themes.dark, fontsDisplay);\n const fontsCSSPath = path.join(outputDir, \"fonts.css\");\n fs.writeFileSync(fontsCSSPath, fontsCSS);\n console.log(`✓ Generated fonts CSS: ${fontsCSSPath}`);\n\n const output: string[] = [];\n\n // Generate @theme block with fonts from both themes\n output.push(generateThemeBlock(themes.light, themes.dark));\n output.push(\"\");\n\n // IMPORTANT; Place dark theme first OTHERWISE daisyUI will not apply it correctly\n // @see https://github.com/saadeghi/daisyui/issues/3921#issuecomment-3059524563\n // Generate @theme block for dark theme if present\n if (themes.dark) {\n output.push(\"/* Dark theme variables */\");\n output.push('@plugin \"daisyui/theme\" {');\n output.push(generateThemeVariables(themes.dark, \"dark\", themes.default));\n output.push(\"}\");\n output.push(\"\");\n }\n\n // Generate @theme block for light theme\n if (themes.light?.id !== themes.dark?.id) {\n output.push(\"/* Light theme variables */\");\n output.push('@plugin \"daisyui/theme\" {');\n output.push(generateThemeVariables(themes.light, \"light\", themes.default));\n output.push(\"}\");\n output.push(\"\");\n }\n\n // Write the generated CSS file\n const cssContent = output.join(\"\\n\");\n fs.writeFileSync(opts.outputPath, cssContent);\n\n console.log(`✓ Generated theme CSS: ${opts.outputPath}`);\n },\n },\n };\n});\n\nexport default upstartTheme.vite;\n"],"mappings":"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"}
1
+ {"version":3,"file":"vite-plugin-upstart-theme.js","names":["googleFonts: Array<GoogleFont>","lines: string[]","output: string[]"],"sources":["../src/vite-plugin-upstart-theme.ts"],"sourcesContent":["import { createUnplugin } from \"unplugin\";\nimport {\n GenericFont,\n GoogleFont,\n type Theme,\n fontStacksFonts,\n processTheme,\n} from \"@upstart.gg/sdk/themes/theme\";\nimport fs from \"fs\";\nimport path from \"path\";\n\ninterface PluginOptions {\n themes: {\n light: Theme;\n dark?: Theme;\n default: \"light\" | \"dark\";\n };\n outputPath: string;\n /** Google Fonts display parameter (default: 'swap') */\n fontsDisplay?: \"auto\" | \"block\" | \"swap\" | \"fallback\" | \"optional\";\n}\n\n/**\n * Collects Google Fonts from a theme's typography configuration\n */\nfunction collectGoogleFonts(theme: Theme) {\n const { typography } = theme;\n if (!typography) return [];\n\n const googleFonts: Array<GoogleFont> = [];\n const seen = new Set<string>();\n\n const addFont = (font?: GenericFont) => {\n if (font?.type === \"google\" && !seen.has(font.family)) {\n seen.add(font.family);\n googleFonts.push(font);\n }\n };\n\n addFont(typography.sans);\n addFont(typography.serif);\n if (typography.others) {\n Object.values(typography.others).forEach(addFont);\n }\n\n return googleFonts;\n}\n\n/**\n * Generates the fonts.css file content with Google Fonts imports\n */\nfunction generateFontsCSS(\n lightTheme: Theme,\n darkTheme: Theme | null = null,\n display: \"auto\" | \"block\" | \"swap\" | \"fallback\" | \"optional\" = \"swap\",\n): string {\n // Collect fonts from both themes\n const allFonts = new Map<string, GoogleFont>();\n\n for (const font of collectGoogleFonts(lightTheme)) {\n allFonts.set(font.family, font);\n }\n\n if (darkTheme) {\n for (const font of collectGoogleFonts(darkTheme)) {\n allFonts.set(font.family, font);\n }\n }\n\n if (allFonts.size === 0) {\n return \"/* No Google Fonts to import */\\n\";\n }\n\n // Build the Google Fonts URL\n const families = Array.from(allFonts.values()).map((font) => {\n const name = font.family.replace(/ /g, \"+\");\n if (font.weights && font.weights.length > 1 && font.weights[0] !== font.weights.at(-1)) {\n return `family=${name}:wght@${font.weights[0]}..${font.weights.at(-1)}`;\n }\n return `family=${name}`;\n });\n\n const url = `https://fonts.googleapis.com/css2?${families.join(\"&\")}&display=${display}`;\n\n return `/* Google Fonts - Auto-generated by vite-plugin-upstart-theme */\\n@import url(\"${url}\");\\n`;\n}\n\n/**\n * Converts a font definition to a CSS font-family string\n */\nfunction fontToCss(font: Theme[\"typography\"][\"sans\"]): string {\n if (!font) return \"\";\n\n if (font.type === \"stack\") {\n return fontStacksFonts[font.family];\n }\n\n if (font.type === \"google\") {\n // For Google fonts, we just use the family name\n // The actual font loading will be handled separately\n return `\"${font.family}\", system-ui, sans-serif`;\n }\n\n return \"\";\n}\n\n/**\n * Converts camelCase to kebab-case\n */\nfunction camelToKebab(str: string): string {\n return str.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n}\n\n/**\n * Generates @theme block with font definitions\n */\nfunction generateThemeBlock(\n lightTheme: Theme,\n darkTheme: Theme | null = null,\n defaultTheme: \"light\" | \"dark\" = \"light\",\n): string {\n const fontDefinitions = new Map<string, string>();\n\n // Process light theme fonts\n const lightTypography = lightTheme.typography;\n\n // Add sans font\n if (lightTypography.sans) {\n const fontCss = fontToCss(lightTypography.sans);\n if (fontCss) {\n fontDefinitions.set(\"sans\", fontCss);\n }\n }\n\n // Add serif font\n if (lightTypography.serif) {\n const fontCss = fontToCss(lightTypography.serif);\n if (fontCss) {\n fontDefinitions.set(\"serif\", fontCss);\n }\n }\n\n // Add other fonts\n if (lightTypography.others) {\n for (const [name, font] of Object.entries(lightTypography.others)) {\n const fontCss = fontToCss(font);\n if (fontCss) {\n fontDefinitions.set(name, fontCss);\n }\n }\n }\n\n // Process dark theme fonts if provided\n if (darkTheme) {\n const darkTypography = darkTheme.typography;\n\n if (darkTypography.sans) {\n const fontCss = fontToCss(darkTypography.sans);\n if (fontCss) {\n fontDefinitions.set(\"sans\", fontCss);\n }\n }\n\n if (darkTypography.serif) {\n const fontCss = fontToCss(darkTypography.serif);\n if (fontCss) {\n fontDefinitions.set(\"serif\", fontCss);\n }\n }\n\n if (darkTypography.others) {\n for (const [name, font] of Object.entries(darkTypography.others)) {\n const fontCss = fontToCss(font);\n if (fontCss) {\n fontDefinitions.set(name, fontCss);\n }\n }\n }\n }\n\n const fontLines = Array.from(fontDefinitions.entries())\n .map(([name, value]) => ` --font-${name}: ${value};`)\n .join(\"\\n\");\n\n return `/* Fonts in the tailwind @theme block */\n@theme {\n ${fontLines}\n}\n\n/* Exclude properties since it produce warnings and is not important */\n@plugin \"daisyui\" {\n exclude: properties;\n themes: ${lightTheme.id} ${defaultTheme === \"light\" || !darkTheme ? \"--default\" : \"\"}${darkTheme?.id && darkTheme?.id !== lightTheme.id ? `, ${darkTheme.id} ${defaultTheme === \"dark\" ? \"--default\" : \"--prefersdark\"}` : \"\"};\n logs: true;\n}\n`;\n}\n\n//\n\n/**\n * Generates @theme block for a single theme with colors and layout variables\n */\nfunction generateThemeVariables(\n theme: Theme,\n type: \"light\" | \"dark\",\n defaultTheme: \"light\" | \"dark\",\n): string {\n const processed = processTheme(theme);\n const lines: string[] = [\n ` name: \"${processed.id}\";`,\n ` color-scheme: ${processed.browserColorScheme};`,\n ...((defaultTheme === \"dark\" && theme.browserColorScheme === \"dark\") ||\n (defaultTheme === \"light\" && theme.browserColorScheme === \"light\")\n ? [` default: true;`]\n : []),\n // ...(type === \"dark\" && defaultTheme !== \"dark\" ? [` prefersdark: true;`] : [` prefersdark: false;`]),\n ];\n\n // Color variables\n for (const [colorKey, colorValue] of Object.entries(processed.colors)) {\n const kebabKey = [\"base100\", \"base200\", \"base300\"].includes(colorKey)\n ? colorKey.replace(\"base\", \"base-\")\n : camelToKebab(colorKey);\n lines.push(` --color-${kebabKey}: ${colorValue};`);\n }\n\n lines.push(\"\");\n\n // Layout variables\n lines.push(` --radius-selector: ${processed.radiusSelector};`);\n lines.push(` --radius-field: ${processed.radiusField};`);\n lines.push(` --radius-box: ${processed.radiusBox};`);\n lines.push(` --size-selector: ${processed.sizeSelector};`);\n lines.push(` --size-field: ${processed.sizeField};`);\n lines.push(` --border: ${processed.border};`);\n lines.push(` --depth: ${processed.depth ? 1 : 0};`);\n lines.push(` --noise: 0;`);\n\n // return the generated lines\n return lines.join(\"\\n\");\n}\n\n/**\n * Unplugin-based theme generator\n */\nexport const upstartTheme = createUnplugin<PluginOptions>((opts) => {\n let generated = false;\n\n return {\n name: \"unplugin-theme-generator\",\n apply: \"serve\",\n\n vite: {\n configResolved() {\n // Generate the CSS file once when config is resolved\n if (generated) return;\n generated = true;\n\n if (!opts?.themes?.light) {\n console.warn(\"No light theme provided to unplugin-theme-generator. A light theme is required.\");\n return;\n }\n\n const outputDir = path.dirname(opts.outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n const { themes, fontsDisplay = \"swap\" } = opts;\n\n // Generate fonts.css file\n const fontsCSS = generateFontsCSS(themes.light, themes.dark, fontsDisplay);\n const fontsCSSPath = path.join(outputDir, \"fonts.css\");\n fs.writeFileSync(fontsCSSPath, fontsCSS);\n\n const output: string[] = [];\n\n // Generate @theme block with fonts from both themes\n output.push(generateThemeBlock(themes.light, themes.dark));\n output.push(\"\");\n\n // IMPORTANT; Place dark theme first OTHERWISE daisyUI will not apply it correctly\n // @see https://github.com/saadeghi/daisyui/issues/3921#issuecomment-3059524563\n // Generate @theme block for dark theme if present\n if (themes.dark) {\n output.push(\"/* Dark theme variables */\");\n output.push('@plugin \"daisyui/theme\" {');\n output.push(generateThemeVariables(themes.dark, \"dark\", themes.default));\n output.push(\"}\");\n output.push(\"\");\n }\n\n // Generate @theme block for light theme\n if (themes.light?.id !== themes.dark?.id) {\n output.push(\"/* Light theme variables */\");\n output.push('@plugin \"daisyui/theme\" {');\n output.push(generateThemeVariables(themes.light, \"light\", themes.default));\n output.push(\"}\");\n output.push(\"\");\n }\n\n // Write the generated CSS file\n const cssContent = output.join(\"\\n\");\n fs.writeFileSync(opts.outputPath, cssContent);\n },\n },\n };\n});\n\nexport default upstartTheme.vite;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upstart.gg/vite-plugins",
3
- "version": "0.0.38",
3
+ "version": "0.0.40",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -23,7 +23,7 @@
23
23
  "oxc-parser": "^0.101.0",
24
24
  "unplugin": "^2.3.11",
25
25
  "zimmerframe": "^1.1.4",
26
- "@upstart.gg/sdk": "^0.0.38"
26
+ "@upstart.gg/sdk": "^0.0.40"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/bun": "1.3.5",
@@ -37,10 +37,15 @@
37
37
  "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.53"
38
38
  },
39
39
  "exports": {
40
+ "./upstart-editor-api": "./dist/upstart-editor-api.js",
40
41
  "./vite-plugin-upstart-attrs": "./dist/vite-plugin-upstart-attrs.js",
42
+ "./vite-plugin-upstart-branding/plugin": "./dist/vite-plugin-upstart-branding/plugin.js",
43
+ "./vite-plugin-upstart-branding/runtime": "./dist/vite-plugin-upstart-branding/runtime.js",
44
+ "./vite-plugin-upstart-branding/types": "./dist/vite-plugin-upstart-branding/types.js",
41
45
  "./vite-plugin-upstart-editor/plugin": "./dist/vite-plugin-upstart-editor/plugin.js",
42
46
  "./vite-plugin-upstart-editor/runtime": "./dist/vite-plugin-upstart-editor/runtime/index.js",
43
47
  "./vite-plugin-upstart-editor/runtime/click-handler": "./dist/vite-plugin-upstart-editor/runtime/click-handler.js",
48
+ "./vite-plugin-upstart-editor/runtime/error-handler": "./dist/vite-plugin-upstart-editor/runtime/error-handler.js",
44
49
  "./vite-plugin-upstart-editor/runtime/hover-overlay": "./dist/vite-plugin-upstart-editor/runtime/hover-overlay.js",
45
50
  "./vite-plugin-upstart-editor/runtime/text-editor": "./dist/vite-plugin-upstart-editor/runtime/text-editor.js",
46
51
  "./vite-plugin-upstart-editor/runtime/types": "./dist/vite-plugin-upstart-editor/runtime/types.js",
@@ -49,7 +54,8 @@
49
54
  "./package.json": "./package.json"
50
55
  },
51
56
  "peerDependencies": {
52
- "@upstart.gg/sdk": "^0.0.38"
57
+ "zod": "4.2.1",
58
+ "@upstart.gg/sdk": "^0.0.40"
53
59
  },
54
60
  "author": "Upstart",
55
61
  "publishConfig": {
@@ -58,6 +64,8 @@
58
64
  "scripts": {
59
65
  "test": "vitest --run",
60
66
  "test:bun": "bun test",
61
- "build": "tsdown"
67
+ "build": "tsdown",
68
+ "lint": "biome check . --write && tsc --noEmit",
69
+ "ci:lint": "biome check . && tsc --noEmit"
62
70
  }
63
71
  }