From c6bbd0a6f8c5c4efeeb803fc2a8d6fa6a3bf2672 Mon Sep 17 00:00:00 2001 From: Nick Bernal Date: Wed, 26 Nov 2025 16:27:51 -0800 Subject: [PATCH 01/13] feat: super-editor TS migration - infra files --- package-lock.json | 129 +++++++++++++-- .../contracts/src/engines/tabs.ts | 3 - packages/super-editor/package.json | 19 ++- packages/super-editor/src/index.ts | 87 ++++++++++ packages/super-editor/src/main.ts | 8 + packages/super-editor/src/types/ambient.d.ts | 151 ++++++++++++++++++ packages/super-editor/src/types/uuid.d.ts | 3 + packages/super-editor/tsconfig.strict.json | 24 +++ packages/super-editor/tsconfig.test.json | 10 ++ 9 files changed, 414 insertions(+), 20 deletions(-) create mode 100644 packages/super-editor/src/index.ts create mode 100644 packages/super-editor/src/main.ts create mode 100644 packages/super-editor/src/types/ambient.d.ts create mode 100644 packages/super-editor/src/types/uuid.d.ts create mode 100644 packages/super-editor/tsconfig.strict.json create mode 100644 packages/super-editor/tsconfig.test.json diff --git a/package-lock.json b/package-lock.json index 432447121..088c33932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3967,6 +3967,35 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.25", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", @@ -4047,6 +4076,43 @@ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, + "node_modules/@vue/language-core": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.1.5.tgz", + "integrity": "sha512-FMcqyzWN+sYBeqRMWPGT2QY0mUasZMVIuHvmb5NT3eeqPrbHBYtCP8JWEUCDCgM+Zr62uuWY/qoeBrPrzfa78w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.0.0", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@vue/reactivity": { "version": "3.5.25", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.25.tgz", @@ -4231,6 +4297,13 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/alien-signals": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-3.1.1.tgz", + "integrity": "sha512-ogkIWbVrLwKtHY6oOAXaYkAxP+cTH7V5FZ5+Tm4NZFd8VDZ6uNMDrfzqctTZ42eTMCSR3ne3otpcxmqSnFfPYA==", + "dev": true, + "license": "MIT" + }, "node_modules/ansi-escapes": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", @@ -5258,8 +5331,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "devOptional": true, "license": "ISC", + "optional": true, "engines": { "node": ">=10" } @@ -8417,8 +8490,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -8430,8 +8503,8 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -12156,8 +12229,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -12170,8 +12243,8 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -12218,6 +12291,13 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -19130,8 +19210,8 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -19208,8 +19288,8 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "devOptional": true, "license": "ISC", + "optional": true, "engines": { "node": ">=8" } @@ -21791,6 +21871,13 @@ "vue": "^3.0.0" } }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, "node_modules/vue": { "version": "3.5.25", "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.25.tgz", @@ -21845,6 +21932,23 @@ } } }, + "node_modules/vue-tsc": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.1.5.tgz", + "integrity": "sha512-L/G9IUjOWhBU0yun89rv8fKqmKC+T0HfhrFjlIml71WpfBv9eb4E9Bev8FMbyueBIU9vxQqbd+oOsVcDa5amGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.23", + "@vue/language-core": "3.1.5" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, "node_modules/vueuc": { "version": "0.4.65", "resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.65.tgz", @@ -22342,8 +22446,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/yaml": { "version": "2.8.1", @@ -25261,6 +25365,8 @@ }, "devDependencies": { "@floating-ui/dom": "^1.7.0", + "@typescript-eslint/eslint-plugin": "^8.48.0", + "@typescript-eslint/parser": "^8.48.0", "@vitejs/plugin-vue": "^5.0.4", "@vue/test-utils": "^2.4.6", "postcss-nested": "^6.0.1", @@ -25270,7 +25376,8 @@ "typescript": "^5.7.3", "vite": "^6.3.5", "vite-plugin-node-polyfills": "^0.24.0", - "vitest": "^3.2.4" + "vitest": "^3.2.4", + "vue-tsc": "^3.1.5" }, "peerDependencies": { "@floating-ui/dom": "^1.7.0", @@ -25294,7 +25401,7 @@ } }, "packages/superdoc": { - "version": "0.31.3", + "version": "0.31.4-RC.1", "license": "AGPL-3.0", "dependencies": { "buffer-crc32": "^1.0.0", diff --git a/packages/layout-engine/contracts/src/engines/tabs.ts b/packages/layout-engine/contracts/src/engines/tabs.ts index 5cb9ebe8e..6c2ad2a05 100644 --- a/packages/layout-engine/contracts/src/engines/tabs.ts +++ b/packages/layout-engine/contracts/src/engines/tabs.ts @@ -337,9 +337,6 @@ export function calculateTabWidth(params: CalculateTabWidthParams): CalculateTab const beforeWidth = measureText ? measureText(before) : 0; width -= beforeWidth; } - } else if (alignment === 'bar') { - // Bar tabs render a vertical line at the stop; width is zero advance. - width = 0; } if (width < 1) { diff --git a/packages/super-editor/package.json b/packages/super-editor/package.json index 9d832fd35..475615cc0 100644 --- a/packages/super-editor/package.json +++ b/packages/super-editor/package.json @@ -45,6 +45,10 @@ "build": "vite build", "build:watch": "vite build --watch", "types:check": "tsc --noEmit", + "types:check:strict": "tsc -p tsconfig.strict.json", + "types:check:vue": "vue-tsc --noEmit", + "types:check:test": "tsc -p tsconfig.test.json", + "types:check:all": "npm run types:check:strict && npm run types:check:vue && npm run types:check:test", "types:build": "tsc -p tsconfig.build.json", "test": "vitest", "test:debug": "vitest --inspect-brk --pool threads --poolOptions.threads.singleThread", @@ -53,13 +57,13 @@ "pack": "rm *.tgz 2>/dev/null || true && npm run build && npm pack && mv harbour-enterprises-super-editor-0.0.1-alpha.0.tgz ./super-editor.tgz" }, "dependencies": { - "@superdoc/word-layout": "*", - "@superdoc/pm-adapter": "*", - "@superdoc/layout-bridge": "*", - "@superdoc/url-validation": "*", - "@superdoc/painter-dom": "*", "@superdoc/contracts": "*", + "@superdoc/layout-bridge": "*", "@superdoc/measuring-dom": "*", + "@superdoc/painter-dom": "*", + "@superdoc/pm-adapter": "*", + "@superdoc/url-validation": "*", + "@superdoc/word-layout": "*", "buffer-crc32": "^1.0.0", "color2k": "^2.0.3", "eventemitter3": "^5.0.1", @@ -98,6 +102,8 @@ }, "devDependencies": { "@floating-ui/dom": "^1.7.0", + "@typescript-eslint/eslint-plugin": "^8.48.0", + "@typescript-eslint/parser": "^8.48.0", "@vitejs/plugin-vue": "^5.0.4", "@vue/test-utils": "^2.4.6", "postcss-nested": "^6.0.1", @@ -107,6 +113,7 @@ "typescript": "^5.7.3", "vite": "^6.3.5", "vite-plugin-node-polyfills": "^0.24.0", - "vitest": "^3.2.4" + "vitest": "^3.2.4", + "vue-tsc": "^3.1.5" } } diff --git a/packages/super-editor/src/index.ts b/packages/super-editor/src/index.ts new file mode 100644 index 000000000..eb355ada5 --- /dev/null +++ b/packages/super-editor/src/index.ts @@ -0,0 +1,87 @@ +import './style.css'; +import { SuperConverter } from './core/super-converter/SuperConverter'; +import { getMarksFromSelection } from './core/helpers/getMarksFromSelection.js'; +import { getActiveFormatting } from './core/helpers/getActiveFormatting.js'; +import { getStarterExtensions, getRichTextExtensions } from './extensions/index.js'; +import { SuperToolbar } from './components/toolbar/super-toolbar.js'; +import { DocxZipper, helpers } from './core/index.js'; +import { Editor } from './core/Editor.js'; +import { PresentationEditor } from './core/PresentationEditor.js'; +import { createZip } from './core/super-converter/zipper.js'; +import { getAllowedImageDimensions } from './extensions/image/imageHelpers/processUploadedImage.js'; +import { Node, Attribute } from '@core/index.js'; +import { Extension } from '@core/Extension.js'; +import { Plugin, PluginKey } from 'prosemirror-state'; +import { Mark } from '@core/Mark.js'; +import SlashMenu from './components/slash-menu/SlashMenu.vue'; +import BasicUpload from '@superdoc/common/components/BasicUpload.vue'; + +import SuperEditor from './components/SuperEditor.vue'; +import Toolbar from './components/toolbar/Toolbar.vue'; +import SuperInput from './components/SuperInput.vue'; +import AIWriter from './components/toolbar/AIWriter.vue'; +import * as fieldAnnotationHelpers from './extensions/field-annotation/fieldAnnotationHelpers/index.js'; +import * as trackChangesHelpers from './extensions/track-changes/trackChangesHelpers/index.js'; +import { TrackChangesBasePluginKey } from './extensions/track-changes/plugins/index.js'; +import { CommentsPluginKey } from './extensions/comment/comments-plugin.js'; +import { AnnotatorHelpers } from '@helpers/annotator.js'; +import { SectionHelpers } from '@extensions/structured-content/document-section/index.js'; +import { registeredHandlers } from './core/super-converter/v3/handlers/index.js'; +import { Decoration, DecorationSet } from 'prosemirror-view'; + +const Extensions = { + Node, + Attribute, + Extension, + Mark, + // + Plugin, + PluginKey, + Decoration, + DecorationSet, +}; + +/** + * Exported classes and components. + * @module exports + * @see SuperConverter + * @see DocxZipper + * @see SuperEditor + * @see Toolbar + * @see AIWriter + */ +export { + // Classes + SuperConverter, + DocxZipper, + SuperToolbar, + Editor, + PresentationEditor, + + // Components + SuperEditor, + SuperInput, + BasicUpload, + Toolbar, + AIWriter, + SlashMenu, + + // Helpers + helpers, + fieldAnnotationHelpers, + trackChangesHelpers, + AnnotatorHelpers, + SectionHelpers, + getMarksFromSelection, + getActiveFormatting, + getStarterExtensions, + getRichTextExtensions, + createZip, + getAllowedImageDimensions, + registeredHandlers, + + // External extensions classes + Extensions, + TrackChangesBasePluginKey, + CommentsPluginKey, +}; diff --git a/packages/super-editor/src/main.ts b/packages/super-editor/src/main.ts new file mode 100644 index 000000000..5990af181 --- /dev/null +++ b/packages/super-editor/src/main.ts @@ -0,0 +1,8 @@ +import './dev/style.css'; +import { createApp } from 'vue'; +import { vClickOutside } from '@superdoc/common'; +import DeveloperPlayground from './dev/components/DeveloperPlayground.vue'; + +const app = createApp(DeveloperPlayground); +app.directive('click-outside', vClickOutside); +app.mount('#app'); diff --git a/packages/super-editor/src/types/ambient.d.ts b/packages/super-editor/src/types/ambient.d.ts new file mode 100644 index 000000000..f383ebfb2 --- /dev/null +++ b/packages/super-editor/src/types/ambient.d.ts @@ -0,0 +1,151 @@ +// Temporary ambient declarations for modules that need type declarations +// SVG imports with ?raw suffix +declare module '*.svg?raw' { + const content: string; + export default content; +} + +// Vue component declarations for relative imports +declare module '*.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +// Path alias declarations +declare module '@/utils/headless-helpers.js' { + import type { Editor } from '../core/Editor.js'; + export const isHeadless: (editor: Editor | null | undefined) => boolean; + export const shouldSkipNodeView: (editor: Editor | null | undefined) => boolean; +} + +declare module '@superdoc/common/icons/*.svg?raw' { + const content: string; + export default content; +} + +declare module './extensions/index.js' { + const value: any; + export default value; + export const getStarterExtensions: any; + export const getRichTextExtensions: any; +} + +declare module './core/super-converter/SuperConverter' { + export class SuperConverter { + [key: string]: any; + } +} + +declare module './core/super-converter/zipper.js' { + export const createZip: any; +} + +declare module './extensions/image/imageHelpers/processUploadedImage.js' { + export const getAllowedImageDimensions: any; +} + +declare module './extensions/field-annotation/fieldAnnotationHelpers/index.js' { + export const fieldAnnotationHelpers: any; +} + +declare module './extensions/track-changes/trackChangesHelpers/index.js' { + export const trackChangesHelpers: any; +} + +declare module './extensions/track-changes/plugins/index.js' { + export const TrackChangesBasePluginKey: any; +} + +declare module './extensions/comment/comments-plugin.js' { + export const CommentsPluginKey: any; +} + +declare module '@helpers/annotator.js' { + export const AnnotatorHelpers: any; +} + +declare module '@extensions/structured-content/document-section/index.js' { + export const SectionHelpers: any; +} + +declare module './core/super-converter/v3/handlers/index.js' { + export const registeredHandlers: any; +} + +declare module './components/toolbar/super-toolbar.js' { + export const SuperToolbar: any; +} + +declare module '@superdoc/common/components/BasicUpload.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module './components/slash-menu/SlashMenu.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module './components/SuperEditor.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module './components/toolbar/Toolbar.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module './components/SuperInput.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module './components/toolbar/AIWriter.vue' { + import { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} + +// Path aliases for @ imports +declare module '@/index.js' { + export * from '../index.js'; +} + +declare module '@/core/PresentationEditor.js' { + export * from '../core/PresentationEditor.js'; +} + +declare module '@/core/Editor.js' { + export * from '../core/Editor.js'; +} + +declare module '@/core/helpers/getMarkRange.js' { + export * from '../core/helpers/getMarkRange.js'; +} + +declare module '@/utils/styleIsolation.js' { + export const createElementInContext: any; + export const createStyleContext: any; +} + +// External module declarations +declare module '@superdoc/common/data/blank.docx?url' { + const url: string; + export default url; +} + +declare module '@superdoc/common/icons/*.svg' { + const content: string; + export default content; +} + +declare module '@tiptap/pm/model' { + export * from 'prosemirror-model'; +} diff --git a/packages/super-editor/src/types/uuid.d.ts b/packages/super-editor/src/types/uuid.d.ts new file mode 100644 index 000000000..1fc81715a --- /dev/null +++ b/packages/super-editor/src/types/uuid.d.ts @@ -0,0 +1,3 @@ +declare module 'uuid' { + export function v4(): string; +} diff --git a/packages/super-editor/tsconfig.strict.json b/packages/super-editor/tsconfig.strict.json new file mode 100644 index 000000000..5592bb962 --- /dev/null +++ b/packages/super-editor/tsconfig.strict.json @@ -0,0 +1,24 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": false, + "allowJs": true, + "noEmit": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts", "src/**/*.vue"], + "exclude": [ + "node_modules", + "dist", + "**/*.test.ts", + "**/__tests__/**/*", + "src/core/super-converter/**/*", + "src/core/super-validator/**/*" + ] +} diff --git a/packages/super-editor/tsconfig.test.json b/packages/super-editor/tsconfig.test.json new file mode 100644 index 000000000..b08e9add9 --- /dev/null +++ b/packages/super-editor/tsconfig.test.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.strict.json", + "compilerOptions": { + "types": ["vitest/globals", "node"], + "noUnusedLocals": false, + "noUnusedParameters": false + }, + "include": ["src/**/*.test.ts", "src/tests/**/*.ts"], + "exclude": ["node_modules", "dist", "src/core/super-converter/**/*"] +} From 99784edc87dcf0a3066af6aa90081f345f8550b5 Mon Sep 17 00:00:00 2001 From: Nick Bernal Date: Wed, 26 Nov 2025 16:28:25 -0800 Subject: [PATCH 02/13] feat: ts migration - super-editor utils --- .../{contextmenu-helpers.js => contextmenu-helpers.ts} | 6 +++--- .../utils/{headless-helpers.js => headless-helpers.ts} | 10 ++++++---- packages/super-editor/src/utils/styleIsolation.d.ts | 1 - .../src/utils/{styleIsolation.js => styleIsolation.ts} | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) rename packages/super-editor/src/utils/{contextmenu-helpers.js => contextmenu-helpers.ts} (81%) rename packages/super-editor/src/utils/{headless-helpers.js => headless-helpers.ts} (61%) delete mode 100644 packages/super-editor/src/utils/styleIsolation.d.ts rename packages/super-editor/src/utils/{styleIsolation.js => styleIsolation.ts} (73%) diff --git a/packages/super-editor/src/utils/contextmenu-helpers.js b/packages/super-editor/src/utils/contextmenu-helpers.ts similarity index 81% rename from packages/super-editor/src/utils/contextmenu-helpers.js rename to packages/super-editor/src/utils/contextmenu-helpers.ts index 0bd8f54b0..3c27e6998 100644 --- a/packages/super-editor/src/utils/contextmenu-helpers.js +++ b/packages/super-editor/src/utils/contextmenu-helpers.ts @@ -1,4 +1,4 @@ -const isKeyboardInvocation = (event) => { +const isKeyboardInvocation = (event: MouseEvent): boolean => { return ( event.type === 'contextmenu' && typeof event.detail === 'number' && @@ -9,7 +9,7 @@ const isKeyboardInvocation = (event) => { ); }; -const prefersNativeMenu = (event) => { +const prefersNativeMenu = (event: MouseEvent | null | undefined): boolean => { if (!event) return false; if (event.ctrlKey || event.metaKey) { @@ -26,7 +26,7 @@ const prefersNativeMenu = (event) => { * @param {MouseEvent} event * @returns {boolean} */ -const shouldAllowNativeContextMenu = (event) => { +const shouldAllowNativeContextMenu = (event: MouseEvent): boolean => { return prefersNativeMenu(event); }; diff --git a/packages/super-editor/src/utils/headless-helpers.js b/packages/super-editor/src/utils/headless-helpers.ts similarity index 61% rename from packages/super-editor/src/utils/headless-helpers.js rename to packages/super-editor/src/utils/headless-helpers.ts index 51e99ea1c..ec222bf54 100644 --- a/packages/super-editor/src/utils/headless-helpers.js +++ b/packages/super-editor/src/utils/headless-helpers.ts @@ -1,19 +1,21 @@ +import type { Editor } from '../core/Editor.js'; + /** * Check if editor is in headless mode. * This is used to allow for the future movement of the headless mode config, * can update once here and fixed in all locations in the applicaiton. - * @param {import('../core/Editor.js').Editor} editor - The editor instance. + * @param {Editor} editor - The editor instance. * @returns {boolean} - Whether the editor is in headless mode. */ -export const isHeadless = (editor) => { +export const isHeadless = (editor: Editor | null | undefined): boolean => { return editor?.options?.isHeadless ?? false; }; /** * Determine if the node view should be skipped in headless mode. - * @param {import('../core/Editor.js').Editor} editor - The editor instance. + * @param {Editor} editor - The editor instance. * @returns {boolean} - Whether the node view should be skipped. */ -export const shouldSkipNodeView = (editor) => { +export const shouldSkipNodeView = (editor: Editor | null | undefined): boolean => { return isHeadless(editor); }; diff --git a/packages/super-editor/src/utils/styleIsolation.d.ts b/packages/super-editor/src/utils/styleIsolation.d.ts deleted file mode 100644 index 7569963c2..000000000 --- a/packages/super-editor/src/utils/styleIsolation.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function applyStyleIsolationClass(...args: any[]): any; diff --git a/packages/super-editor/src/utils/styleIsolation.js b/packages/super-editor/src/utils/styleIsolation.ts similarity index 73% rename from packages/super-editor/src/utils/styleIsolation.js rename to packages/super-editor/src/utils/styleIsolation.ts index 7df558b0d..525e74bce 100644 --- a/packages/super-editor/src/utils/styleIsolation.js +++ b/packages/super-editor/src/utils/styleIsolation.ts @@ -4,7 +4,7 @@ export const STYLE_ISOLATION_CLASS = 'sd-editor-scoped'; * Apply the editor style-isolation class to a DOM element. * @param {HTMLElement} target */ -export const applyStyleIsolationClass = (target) => { +export const applyStyleIsolationClass = (target: HTMLElement | null | undefined): void => { if (!target || !target.classList) return; target.classList.add(STYLE_ISOLATION_CLASS); }; From 3cf60d49d492fe62fdfb1c77b514fc9d0b537eea Mon Sep 17 00:00:00 2001 From: Nick Bernal Date: Wed, 26 Nov 2025 16:37:22 -0800 Subject: [PATCH 03/13] feat: ts migration - super-editor vue components --- .../src/components/SuperEditor.vue | 2 +- .../src/components/SuperInput.vue | 61 ++-- .../src/components/TableResizeOverlay.vue | 78 ++++- .../{cursor-helpers.js => cursor-helpers.ts} | 43 ++- ...ation-helpers.js => pagination-helpers.ts} | 12 +- .../components/popovers/GenericPopover.vue | 2 +- .../src/components/popovers/Mentions.vue | 2 +- .../src/components/rulers/Ruler.vue | 2 +- .../src/components/slash-menu/SlashMenu.vue | 2 +- .../slash-menu/{constants.js => constants.ts} | 19 +- .../slash-menu/{menuItems.js => menuItems.ts} | 0 .../slash-menu/{utils.js => utils.ts} | 0 .../src/components/toolbar/AIWriter.vue | 2 +- .../components/toolbar/AlignmentButtons.vue | 2 +- .../src/components/toolbar/ButtonGroup.vue | 2 +- .../src/components/toolbar/DocumentMode.vue | 2 +- .../src/components/toolbar/IconGrid.vue | 2 +- .../src/components/toolbar/IconGridRow.vue | 2 +- .../src/components/toolbar/LinkInput.vue | 2 +- .../src/components/toolbar/LinkedStyle.vue | 2 +- .../src/components/toolbar/OverflowMenu.vue | 2 +- .../src/components/toolbar/SearchInput.vue | 2 +- .../src/components/toolbar/TableActions.vue | 2 +- .../src/components/toolbar/TableGrid.vue | 2 +- .../src/components/toolbar/ToggleSlider.vue | 44 +-- .../src/components/toolbar/Toolbar.vue | 2 +- .../components/toolbar/ToolbarButtonIcon.vue | 24 +- .../components/toolbar/ToolbarSeparator.vue | 23 +- .../toolbar/{ai-helpers.js => ai-helpers.ts} | 147 ++++++--- ...n-helpers.js => color-dropdown-helpers.ts} | 39 ++- .../toolbar/{constants.js => constants.ts} | 22 +- .../{defaultItems.js => defaultItems.ts} | 55 ++-- ...{format-negation.js => format-negation.ts} | 11 +- .../src/components/toolbar/helpers.js | 51 ---- .../src/components/toolbar/helpers.ts | 69 +++++ .../{scroll-helpers.js => scroll-helpers.ts} | 17 +- .../{super-toolbar.js => super-toolbar.ts} | 284 +++++++++++++----- .../{toolbarIcons.js => toolbarIcons.ts} | 2 +- .../{toolbarTexts.js => toolbarTexts.ts} | 2 +- ...se-toolbar-item.js => use-toolbar-item.ts} | 122 +++++++- 40 files changed, 799 insertions(+), 362 deletions(-) rename packages/super-editor/src/components/{cursor-helpers.js => cursor-helpers.ts} (81%) rename packages/super-editor/src/components/{pagination-helpers.js => pagination-helpers.ts} (78%) rename packages/super-editor/src/components/slash-menu/{constants.js => constants.ts} (93%) rename packages/super-editor/src/components/slash-menu/{menuItems.js => menuItems.ts} (100%) rename packages/super-editor/src/components/slash-menu/{utils.js => utils.ts} (100%) rename packages/super-editor/src/components/toolbar/{ai-helpers.js => ai-helpers.ts} (79%) rename packages/super-editor/src/components/toolbar/{color-dropdown-helpers.js => color-dropdown-helpers.ts} (79%) rename packages/super-editor/src/components/toolbar/{constants.js => constants.ts} (83%) rename packages/super-editor/src/components/toolbar/{defaultItems.js => defaultItems.ts} (97%) rename packages/super-editor/src/components/toolbar/{format-negation.js => format-negation.ts} (83%) delete mode 100644 packages/super-editor/src/components/toolbar/helpers.js create mode 100644 packages/super-editor/src/components/toolbar/helpers.ts rename packages/super-editor/src/components/toolbar/{scroll-helpers.js => scroll-helpers.ts} (61%) rename packages/super-editor/src/components/toolbar/{super-toolbar.js => super-toolbar.ts} (86%) rename packages/super-editor/src/components/toolbar/{toolbarIcons.js => toolbarIcons.ts} (99%) rename packages/super-editor/src/components/toolbar/{toolbarTexts.js => toolbarTexts.ts} (96%) rename packages/super-editor/src/components/toolbar/{use-toolbar-item.js => use-toolbar-item.ts} (50%) diff --git a/packages/super-editor/src/components/SuperEditor.vue b/packages/super-editor/src/components/SuperEditor.vue index 0a23c3eb1..50390989f 100644 --- a/packages/super-editor/src/components/SuperEditor.vue +++ b/packages/super-editor/src/components/SuperEditor.vue @@ -1,4 +1,4 @@ -