Typescript port - #85
Merged
Merged
Conversation
Set up the foundation for the JS → TS migration. No source files changed. - tsconfig: strict, react-jsx, bundler resolution, allowJs:true so existing .js keeps compiling during incremental conversion - graphql-codegen: typescript + typescript-operations + typed-document-node plugins, points at live Hasura via VITE_GRAPHQL_ENDPOINT + admin secret - src/types/two.d.ts: module augmentation for Two.js internals we touch (subtractions, _flagSubtractions, renderer.elem, ZUI extras) - src/types/global.d.ts: ImportMetaEnv shape, svgr client types, idx shim - package.json: yarn typecheck (tsc --noEmit) and yarn codegen scripts - @types/react pinned to ^18.3 to match runtime Known: codegen surfaces pre-existing duplicate operation names across queries/subscriptions (MyQuery, getComponentsForBoard, getBoardComponents). Will be resolved when schema files convert in stage 3. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convert src/lib.js → src/lib.ts and add .d.ts companions for the JS files it re-exports. Consumers (craftmaps + future ones) now get real types for the Board component, BoardContext, useBoardContext, and ComponentRecord. New files: - src/types/board.ts: canonical types — BoardProps, BoardContextValue, ComponentRecord (mirrors the Hasura schema), ComponentStore, hook value shapes. Internal-handler signatures stay loose; tightened in stages 4–10 as their source files convert. - src/views/Board/index.d.ts: <Board /> typed as ComponentType<BoardProps>. - src/views/Board/board.d.ts: BoardContext + useBoardContext declarations. Stage 10 will fold this into a typed source and decide on a strict null-throwing useBoardContext. - src/schema/mutations/index.d.ts: INSERT_USER_ONE as DocumentNode shim. - src/utils/misc.d.ts: generateRandomUsernames typed via RandomUsername. package.json: main / module / types / exports flipped to src/lib.ts. Vite consumers resolve .ts via esbuild natively; the link: symlink setup is unaffected. yarn typecheck passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convert all pure-logic + light-Two.js files in src/utils, src/constants, and the root serviceWorker. No behavior changes — just types. Fully typed (pure logic): - src/constants/misc.ts, elementSchema.ts, exportHooks.ts - src/utils/constants.ts (svgr icons typed as FunctionComponent<SVGProps>) - src/utils/drawModeUtils.ts, misc.ts, groupInspect.ts, pencilHelper.ts - src/serviceWorker.ts Loose-typed (heavy Two.js interop, narrows in Stages 7–9): - src/utils/updateVertices.ts — Anchor / Commands constructor namespace - src/utils/canvasUtils.ts — scene bookkeeping (.elementData, etc.) - src/utils/applyProperty.ts, applyGroupProperty.ts — selectedComponent scaffolding from canvas Also removed: - src/utils/misc.d.ts shim — superseded by misc.ts as source of truth. yarn typecheck passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GraphQL schema (typed via graphql-codegen):
- Generated src/schema/generated.ts (3109 lines) from the live Hasura
introspection. Mirrors typescript + typescript-operations + typed-document-
node plugins; pinned scalars (uuid→string, bigint→number, jsonb→unknown).
- queries / mutations / subscriptions index files converted to .ts. Each
exported gql is typed as TypedDocumentNode<Result, Variables> from
'@apollo/client', so useQuery / useMutation / useSubscription will infer
the right data and variables shapes once their callers convert.
Pre-existing fixes surfaced by codegen validation:
- Renamed 3 duplicate subscription operations whose names clashed with the
query side:
MyQuery → userDetailsSubscription
getBoardComponents → getBoardComponentsSubscription
getComponentsForBoard → getComponentsForBoardSubscription
- Aligned 5 variable types with the actual schema (no runtime behavior
change — Hasura was already coercing):
$id: uuid → $id: String (users_user.id is String)
$boardId: String(!) → $boardId: uuid(!) (components.boardId is uuid)
- Renamed mutation operation `UPDATE_COMPONENT_INFO` → `updateComponentInfo`
for codegen name parity (camelCase) with the other mutations.
Also removed:
- src/schema/mutations/index.d.ts shim — superseded by the .ts file.
Factories (src/factory/*.ts):
- Main.ts is generic over its properties shape; each factory binds a
concrete shape (RectangleProperties, CircleProperties, DiamondProperties,
DividerProperties, ArrowLineProperties, NewArrowLineProperties,
NewTextProperties, PencilProperties).
- Two.js instance + shape returns are typed loosely (`any`) where the
published Two.js types don't cover the methods/fields we use. These
sharpen in stages 7–9 when scene types converge.
- `parseInt(prevX)` calls wrapped in String() casts to satisfy strict
typing without changing runtime behavior.
yarn typecheck + yarn codegen both pass.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
All six custom hooks now have explicit option/return interfaces. Internal Two.js scene access stays loose; the canvas-side typing converges in Stages 7–9 where these refs originate. Hooks: - useMobileToolbarPanels: MobileToolbarPanelsOptions + Api - useDrawingModes: DrawingModeToggleOptions + DrawingModesApi; toggle helpers are explicit Dispatch<SetStateAction<...>> at the boundary - useElementDefaults: ElementDefaultsState + ElementDefaultsApi; TextSizeLabel union for the size enum - useLocalDraftPersistence: LocalDraftPersistenceOptions/Api; ComponentStore + Partial<ComponentStore> at boundaries; PersistedDraft for the on-disk shape - useCanvasClipboard: CanvasClipboardOptions/Api with a SingleClipboardPayload | GroupClipboardPayload union for the in-memory clipboard; per-call casts only where elementData carries arrow/pencil fields not on the shared ComponentRecord - useComponentHistory: HistoryEntry discriminated union over ADD | DELETE | UPDATE_VERTICES | UPDATE_BULK | BATCH. undo/redo dispatchers narrow on .action, removing the need for casts in applyRemove/applyInsert/applyVertices/applyBulkProps/applyBatch. yarn typecheck passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
React components with no Two.js coupling — easy wins. All file extensions
flip to .tsx where there's JSX, and Icon class drops its prop-types
declaration in favor of a TS interface.
Converted:
- src/components/common/portal.tsx — ReactPortal return; parent ?? document.body
fix (TS flagged the always-truthy method-reference check on appendChild)
- src/components/common/spinnerWithSize.tsx — LoaderSize union ('xs'|'sm'|
'md'|'lg'), typed customStyles as CSSProperties
- src/components/common/spinner.tsx
- src/components/common/button.tsx — ButtonIntent / ButtonSize unions
- src/components/common/modal.tsx — typed refs (HTMLDivElement), narrowed
event handlers (KeyboardEvent, MouseEvent), fixed the className={active &&
open && 'active'} expression to return a string
- src/components/common/modalContainer.tsx
- src/components/modals/PermissionErrorModal.tsx
- src/components/modals/StorageLimitModal.tsx
- src/icons/icons.ts — added IconData interface; Record<string, IconData>
- src/icons/icon.tsx — dropped prop-types, used IconProps interface,
optional-chained Icons[icon] lookup so noUncheckedIndexedAccess is safe
yarn typecheck passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sixteen React + class files converted. Internal Two.js scene access stays loose (`any`); canvas-side typing converges in Stages 7–9. Converted (alphabetical): - src/components/ZoomControls.tsx - src/components/sidebar/menuDrawer.tsx - src/components/sidebar/primary.tsx — typed shapeData via ComponentRecord; filled in the DB-required keys (x1/y1/y2, radius, iconStroke, isDummy, createdAt, boardName) that the JS version was relying on Hasura defaults for. No runtime behavior change. - src/components/sidebar/shapesToolbar.tsx — DrawerAnchor interface; uses PrimaryElement type from utils/constants. - src/components/sidebar/shareLinkPopup.tsx - src/components/sidebar/userDetailsPopup.tsx - src/components/sidebar/elementProperties.tsx (577 lines, biggest one) — ResolveSetKeyOptions + ReadEffectiveValuesOptions interfaces; per-row prop shapes (StrokeWidthRow, StrokeTypeRow, TextSizeRow, FontFamilyRow, SectionLabel) typed inline; SETS / SET_LABELS indexed with `as keyof`. - src/components/utils/borderStyleBox.tsx — StrokeTypeValue derived union from STROKE_TYPES `as const`. - src/components/utils/colorPicker.tsx — dropped prop-types - src/components/utils/dragger.ts (heavy Two.js, params kept loose) - src/components/utils/editWrapper.ts - src/components/utils/loader.tsx - src/components/utils/objectSelector.ts (Two.js Selector class) - src/components/utils/opacitySlider.tsx — dropped prop-types - src/components/utils/toolbarConnector.ts - src/components/utils/zoomer.tsx BoardContextValue audit + fixes (`src/types/board.ts`): - persistBoard typed as `() => Promise<string>` (was `() => void`). - addToLocalComponentStore signature corrected to match board.js: `(id: string, type: string, info: ComponentRecord, skipHistory?: boolean) => void`. - updateComponentVerticesInLocalStore signature corrected: `(id, x, y) => void` instead of `(id, Partial<ComponentRecord>)`. - updateComponentBulkPropertiesInLocalStore gains optional skipDbWrite. - CurrentElement narrowed from `unknown` to `string` (active tool name). yarn typecheck passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Nine Two.js-bound React components. Loose ElementProps + ShapeLike `any`
types throughout — these props come from ElementRenderWrapper / canvas /
factories whose internals stay loose during the migration. Stage 12 cleanup
will sweep what we can after newCanvas converges in Stage 9.
Converted:
- src/components/elements/circle.tsx
- src/components/elements/rectangle.tsx
- src/components/elements/diamond.tsx
- src/components/elements/pencil.tsx
- src/components/elements/arrowLine.tsx
- src/components/elements/divider.tsx
- src/components/elements/newText.tsx (largest — text input overlay,
proportional resize via corner handles)
- src/components/elements/groupobject.tsx — focused-group orchestration;
Two.js scene.subtractions safety pattern from CLAUDE.md preserved
- src/components/utils/elementRenderWrappers.tsx — typed as
ComponentType<ElementProps> factories
Common patterns introduced:
- `useImmer<Record<string, any>>({})` for the internalState bags
- DOM getElementById results captured into `const el = ...; if (el) ...`
blocks rather than chained `.style` access; satisfies strict null checks
- Event handlers receive concrete DOM types (FocusEvent, KeyboardEvent,
MouseEvent) at the boundary; everything past `event.target` falls back to
`any` via cast.
- Two.js constructor-namespace access (Two.Anchor, Two.Commands) goes
through `(Two as any)` since @types/two.js doesn't expose those.
- factoryModules glob updated to '.ts' to match Stage 3's converted
factories.
yarn typecheck passes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
src/canvas/selectionController.ts: 676-line class converted with explicit field declarations, typed listener slots, and a discriminated Interaction union for the scale/rotate handle drag. ShapeAdapter formalized as an interface; SHAPE_ADAPTERS is now Record<string, ShapeAdapter>. Two.js constructor access (Group/Rectangle/Points/Vector) goes through `(Two as any)` since @types/two.js doesn't expose those. yarn typecheck passes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Type addZUI's 15 params, all event handlers (MouseEvent/TouchEvent/
WheelEvent/KeyboardEvent), the Canvas component (React.FC<CanvasProps>),
and Canvas-local callbacks. Two.js scene shapes stay `any` with eslint
disables per the Stage 2/7 convention; refs get explicit nullable
types. resolveShapeFromPath in canvasUtils accepts EventTarget[] since
DOM event paths are EventTarget[], not Element[].
Drive-by: elementModules lookup in handleSetComponentsToRender was
using `\${componentType}.js` after the glob was updated to *.tsx,
which would have silently skipped every component on a fresh render.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Rename board.js → board.tsx. Type BoardContext as <BoardContextValue | undefined>; useBoardContext now throws when called outside <Board />. All useState/useRef nulls get explicit types, callbacks get param types, and Apollo error handlers get any-typed error params per Stage 2/7 convention. Delete board.d.ts shim; types are now sourced from the .tsx file itself. Tighten BoardContextValue: togglePencilMode/Pointer/PanMode and createTextAtSurface get real signatures (were (...args: unknown[])). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Convert App.js, index.js, routes.js, setupTests.js, and all view container/errorBoundary files. Error boundaries get explicit Props/State generics + override modifiers (noImplicitOverride). DOM roots and Sentry context values are null-safe. Delete the views/Board/index.d.ts shim (no longer needed). setupTests imports '@testing-library/jest-dom' directly — the deprecated /extend-expect entrypoint was removed in v6. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- tsconfig: allowJs:false (no straggler .js files in src/; only
src/types/*.d.ts module augmentation remain).
- vite.config.mjs: remove the treat-js-files-as-jsx plugin and the
`'.js': 'jsx'` optimizeDeps loader override — both were JSX-in-.js
workarounds for the migration.
- package.json: drop prop-types and @types/prop-types (no propTypes
blocks remain in src/).
- CLAUDE.md: update file paths to .ts/.tsx, add a TypeScript line to
the Technology Stack, and note the bundler-glob heads-up for
consumers (craftmaps) — `node_modules/craftbase/src/**/*.{ts,tsx}`
replaces the previous .{js,jsx} glob in vite + tailwind content.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
✅ Deploy Preview for craftbase ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Owner
Author
|
Tests failing for either of the reasons
I've validated these all tests by running locally as well as failed test case by checking them on preview app. LGTM. This issue of timeout sometime happens which we can resolve in future. For now, by manual testing i've verified it works as expected. Closing this. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migration from JS-> TS codebase alongside implementing types and interfaces for applicable code carried with help of claude.
Note - Not all of the elements,files or components have implemented full type checking /compliant spec as few of still contain escape hatches using
any(loose migration) . All hooks, components which are needed for board context gets explicit types.