Skip to content

V2 (React 19/Next 16, improve DX, UI improvements, agentic friendly repo,...) - #208

Draft
infi-pc wants to merge 11 commits into
masterfrom
v2
Draft

V2 (React 19/Next 16, improve DX, UI improvements, agentic friendly repo,...)#208
infi-pc wants to merge 11 commits into
masterfrom
v2

Conversation

@infi-pc

@infi-pc infi-pc commented Apr 19, 2026

Copy link
Copy Markdown
Owner

No description provided.

fez and others added 6 commits January 21, 2026 15:06
- Bump version in package.json from 1.3.1 to 1.3.3.
- Add new build scripts for packaging all versions and releasing.
- Introduce debug mode instructions in README.md for better troubleshooting.
- Implement asynchronous element info retrieval in getElementInfo for improved source mapping.
- Enhance error handling in build.js for better build process visibility.
- Add debug logging capabilities to assist in source location issues.
…upport

Merge branch 'dev-feat-supportReact19' from Feahter/locatorjs fork.
Resolve merge conflicts in buildLink.ts and sharedOptionsStore.ts,
combining nvim tmuxSession support with Turbopack [project]/ path
handling and debugMode option.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Translate all Chinese comments and strings to English (14+ files)
- Fix unconditional preventDefault in clickListener (two-phase approach)
- Remove duplicate ReactDevtoolsHook global declaration
- Fix react-devtools-hook build (noEmit: false in tsconfig)
- Add tests for sourceMapResolver (VLQ, mappings, fileUrlToPath)
- Add tests for buildLink Turbopack [project]/ prefix resolution
- Add tests for debug mode toggle and logging
- Export internal functions for testability
- All 44 tests pass, all builds clean

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…umbers

- Options.tsx: Add .catch() to getElementInfoAsync promise chain
- clickSourceResolver.ts: Remove dead clearComponentSourceCache no-op
- clickSourceResolver.ts: Add comments explaining 1500/800 search ranges
- reactAdapter.ts: Remove redundant resolveSourceFromFiber call in diagnose
  (findDebugSourceAsync already calls it internally)
* Add DX/code quality improvements: CI checks, pre-commit hooks, linting

- Add TypeScript type-checking (pnpm ts) to CI
- Add Prettier format check to CI
- Add Playwright e2e tests to CI
- Parallelize CI jobs: format runs independently, typecheck/lint/test/e2e run after build
- Upgrade GitHub Actions from v3 to v4
- Add husky + lint-staged for Prettier pre-commit hook
- Add ESLint to @locator/shared package
- Fix lint errors: @ts-ignore -> @ts-expect-error, console.warn -> console.info
- Add .prettierignore for dist/build/node_modules
- Add turbo build dependency for ts task
- Auto-format existing files to establish baseline

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix: remove explicit pnpm version from action-setup v4

pnpm/action-setup@v4 reads the version from packageManager in package.json.
Specifying version explicitly conflicts with it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix: correct turbo cache path and playwright install in CI

- Turbo v2 cache is at .turbo/cache, not node_modules/.cache/turbo
- Use working-directory for playwright install instead of --filter exec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix: upgrade @playwright/test to ^1.50.0 for CI compatibility

Old version (^1.24.2) requires system dependencies not available on
ubuntu-latest runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
locatorjs Ready Ready Preview, Comment Jul 28, 2026 7:43am

Rework PR #199: React 19/Turbopack support
@infi-pc infi-pc changed the title V2 (React 19, improve DX, UI improvements, agentic friendly repo,...) V2 (React 19/Next 16, improve DX, UI improvements, agentic friendly repo,...) Apr 19, 2026
* Add Playwright e2e tests for React 19 / Turbopack support

9 test cases covering Next.js 16 with webpack and Turbopack:
- Sync resolution via webpack-loader (heading, anchor)
- Async resolution via Turbopack (client components, native elements, server components, nested elements)
- Debug diagnostics verification

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Enhance React 19/Turbopack source resolution with Next.js dev server API fallback

- Add resolveViaNextDevServer() to resolve SSR chunk sources via /__nextjs_original-stack-frames
- Cache Next.js app root resolved from SSR chunk source maps
- Expose parseDebugStack method name and raw URL for API calls
- Add window.locatorDiagnose() helper via registerDiagnose() for debugging element source resolution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix CI: resolve dual @types/react conflict and prettier formatting

Replace bare React.ReactNode with explicit import type { ReactNode } from "react"
in next-16 and next-16-turbopack to avoid pnpm dual-module resolution conflicts.
Also apply prettier to all changed runtime files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix CI: resolve @types/react dual-module conflict in Next.js 16 apps

Root cause: next/dist/styled-jsx/types/css.d.ts resolves 'react' from
pnpm's hoisted store (.pnpm/node_modules/@types/react@18.0.15), making
React@18's global namespace available. The Next.js-generated validator.ts
uses React.ReactNode from this v18 namespace, while our layouts imported
ReactNode from v19 via explicit import — structurally incompatible.

Fix: add tsconfig paths entries to force all 'react' module resolutions
in both next-16 and next-16-turbopack compilations to use the app's own
@types/react@19.2.2, preventing the v18 global namespace from polluting
the TypeScript compilation.

Also apply prettier formatting to all remaining non-conformant files in
packages/runtime and packages/shared.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix ESLint no-console and no-empty-function violations in runtime

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix format violation in README and restore missing e2e test selector text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix merge: remove duplicate registerDiagnose declaration

Auto-merge of origin/v2 left two copies of registerDiagnose in debug.ts,
breaking TypeScript compilation (TS2323) and Babel parsing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Review fixes: CI port wiring, filename assertions, webServer config

- ci.yml: add ports 3352/3353 to port-wait so next-16 and
  next-16-turbopack dev servers are fully booted before Playwright runs
- next16.spec.ts: assert the resolved file path via
  __LOCATORJS_DEBUG_HISTORY__ so a regression mapping elements to the
  wrong file (or chunk URL) fails instead of passing
- playwright.config.ts: add webServer entries for both Next.js 16 apps
  with reuseExistingServer:true, so tests boot their own servers when
  none are running and reuse existing pnpm dev sessions otherwise
- clickSourceResolver.ts: remove clearComponentSourceCache no-op export
  that misrepresented capability; restore original WeakMap comment

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Loosen browser-specific filename assertions in Next.js 16 e2e tests

Different browsers traverse the React _debugOwner chain in different
orders, so the exact file the resolver returns varies (page.tsx vs
components/Card.tsx). Assert the file is inside the app source tree
instead of a specific path. Webpack tests (no debug history populated)
drop the filename assertion entirely — Confirm dialog visibility is
the meaningful signal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…#209)

* Move demo/test projects to test-apps/ and isolate from main pipelines

Relocates the 10 demo apps (vite-*, next-*) from apps/ to test-apps/ so
they no longer share formatting, build, lint, typecheck, or
dependency-version-consistency checks with the shipped packages and
apps (web, extension). Playwright continues to run them via pnpm
workspace filters and the new test-apps:dev script.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Start @locator/web alongside test-apps in e2e CI

Playwright expects the web app on port 3342; the previous pnpm dev &
step was covering it implicitly. After scoping pnpm dev to
packages+apps and introducing pnpm test-apps:dev, the e2e job needs
to launch both.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Apply patch and minor version bumps to all workspace packages.

Security: fixes most high/critical CVEs from pnpm audit.
- next: ^15 → ^15.5.15 (RCE + DoS advisories)
- webpack: ^5.96.1 → ^5.106.2 (SSRF + allowedUris)
- posthog-js: ^1.23.0 → ^1.369.3 (XSS)
- postcss-loader, fs-extra, html-webpack-plugin, terser-webpack-plugin,
  css-loader, sass-loader, source-map-loader, style-loader, ts-loader,
  webpack-dev-server, babel-loader, web-ext (transitive audit hits)

Other notable bumps (all within existing caret ranges):
- @babel/*: 7.26.x → 7.28–7.29.x
- @floating-ui/dom: 1.6.12 → 1.7.6
- @playwright/test: 1.50.0 → 1.59.1
- @typescript-eslint/eslint-plugin: 5.30.6 → 5.62.0
- typescript: 5.6.3 → 5.9.3
- solid-js/babel-preset-solid: 1.9.2/.11 → 1.9.12
- turbo: 2.5.8 → 2.9.6
- lerna: 7.3.0 → 7.4.2
- vitest: 2.1.4 → 2.1.9

Adds `as const` assertion in HtmlElementTreeNode to satisfy the stricter
@typescript-eslint prefer-as-const rule that ships with 5.62.
@mikhailbartashevich

Copy link
Copy Markdown

@infi-pc 👋
Is there a chance React 19 patch to be merged?

* Unify LocatorJS configuration with four-layer resolver (Phase 1)

Collapse fragmented config surfaces (localStorage, chrome.storage, setup() args,
data-* HTML attributes, two settings UIs) into a single canonical type with a
strict per-key priority stack: default < team < user-extension < user-project.

Data model
- Canonical LocatorOptions in @locator/shared with split target fields
  (targetId references targets map; targetTemplate is raw URL, wins over id).
- Pure resolve() returns {effective, provenance} and treats replacePath as an
  atomic value (later layer fully replaces).
- resolveTarget() handles targetTemplate > targetId-in-map > first-target
  fallback with kind discriminator for "unavailable on this site" UX.

Runtime
- optionsStore aggregates four layers via createMemo, exposes effective(),
  provenance(), uiState(), allTargets(), setUserProject(), setUiState().
- Team layer is a live module-scoped signal so late setup() calls re-drive the
  resolver after extension auto-init.
- Call sites simplified: linkTemplateUrl uses resolveTarget; buildLink reads
  effective.projectPath (setInternalProjectPath deleted); modifiers use
  effective.mouseModifiers (data-attribute fallback removed).
- welcomeScreenDismissed moved to nested uiState in user-project blob.
- popupBridge exposes window.__LOCATOR_RUNTIME__ + responds to snapshot and
  site-local-write postMessage protocol; uses onCleanup for prod hygiene.

Extension
- Content script injects window.__LOCATOR_USER_EXTENSION_OPTIONS__ on page load
  and on every chrome.storage change, plus postMessage broadcast (no mount race).
- snapshotBridge relays popup<->page requests with requestId + 1s timeout.
- Popup rewired on existing Hope UI (visual rewrite deferred to Phase 2):
  unified syncedState over chrome.storage.local["userOptions"], polls active tab
  snapshot, ProvenanceBadge per row, SiteLocalToggle for "set for this site only".
- Removed: tracking/social/clickCount UI + storage keys, requestEnable round-trip,
  per-attribute data-* bridge, SharePage.

Cleanup, not migration
- Legacy LOCATOR_OPTIONS localStorage key + legacy chrome.storage.local keys
  (target, controls, allowTracking, sharedOnSocialMedia, clickCount,
  enableExperimentalFeatures) removed on first read. Users reset config on v2;
  v2 is unreleased so no data-loss path.

Tests
- 30 shared tests: 16 resolver permutations + split-field target resolution +
  atomic replacePath + cleanup idempotency.
- 11 runtime integration tests: late setup() live update, postMessage and
  storage-event layer updates, user-project override semantics,
  window.enableLocator, atomic replacePath, uiState isolation, team-targets
  override, popup bridge snapshot + site-local-write protocol.
- vitest.config.ts in runtime resolves solid-js via browser conditions so
  reactivity works in jsdom. Extension typecheck clean.

Phase 2 (separate PR): Kobalte + solid-ui rewrite of popover and popup,
Tailwind into Shadow DOM, packages/ui repurposed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Replace solid-icons with lucide-solid + inline GitHub SVG

solid-icons 1.2.0 ships a packaging bug: sub-packages (e.g. solid-icons/bs)
do `import { IconTemplate } from '../lib/index.jsx'` via relative path, which
bypasses package.json `exports` and forces webpack to resolve the raw JSX file.
With babel-loader excluded from node_modules, the build fails to parse JSX.
Vite users avoid this because vite-plugin-solid runs babel across all of
node_modules; webpack/Rsbuild/parcel users hit it.

Switch the two usages to lucide-solid:
- `HiSolidCog` -> `Settings` from lucide-solid
- `BsGithub` -> inline SVG (lucide deliberately removed brand icons for
  trademark reasons), matching the existing inline-SVG pattern in Home.tsx

lucide-solid ships a self-contained ESM bundle with zero relative-jsx imports,
so it works on webpack without any loader hacks. This unblocks the extension
build and keeps Phase 2 (Kobalte) free of node_modules babel-loader workarounds.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Fix CSP-blocked inline script + non-reactive popup page switch

Two extension popup bugs found during manual testing:

1. Content script injected user-extension options via an inline <script> with
   textContent, which violates strict page CSP (script-src 'self' ...). The
   action was blocked, so the runtime never saw extension options. Switch to a
   data attribute on documentElement (data-locator-user-extension-options);
   the runtime reads + JSON.parses it from dataset. No inline execution, works
   under any CSP.

2. Popup "settings" button did nothing: the page switch used a nested ternary
   inside <Show>, which Solid's compiler does not track reliably. Replace with
   <Switch>/<Match> so each branch is a tracked memo.

Tests updated to set/read the dataset attribute instead of a window global.
55 runtime tests pass; extension + runtime build clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Finish config unification: atomic target, user-origin rename, single source

Model fixes on top of the four-layer resolver (pre-Phase-2 cleanup):

- Atomic target slot in resolve(): targetId and targetTemplate are two forms
  of one choice, so a layer that sets either now overrides both fields from
  lower layers. Previously targetTemplate beat targetId across layers, which
  made a team-set template impossible to override by a user picking a named
  target. Within one layer template still wins (resolveTarget).

- Rename layer "user-project" -> "user-origin" (types, LAYER_ORDER, store
  API getUserOriginOptions/setUserOrigin*, popup badge says "this origin").
  The layer lives in the page origin's localStorage; we usually cannot see
  the repo, so name it what it is. Storage key LOCATOR_USER_OPTIONS kept.

- Remove the residual prop path: initRuntime()/initRender() no longer take
  adapter/targets/showIntro and Runtime reads adapterId, targets and
  showIntro from the options store. setup() writes the team layer only,
  leaving the resolver as the single source of truth.

- resolveTarget fallback reason "empty" was overloaded; split into
  "none-selected" (targets exist, nothing chosen) vs "empty" (no targets).

- Popup syncedState: replace callback-style tabs.query/sendMessage +
  chrome.runtime.lastError with promise style, so the Firefox
  (webextension-polyfill-shaped) path is not silently broken.

Tests: 4 new atomic-target cases + none-selected/empty split in shared
(35 pass), runtime 55 pass, extension typecheck + webpack build clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Repurpose @locator/ui + rewrite popup with per-layer settings tabs

packages/ui is now a compiled Solid component library (babel-preset-solid ->
dist, same pipeline as runtime, so webpack consumers need no loader hacks):
- Primitives: Button, Switch (Kobalte), Tabs (Kobalte), TextInput,
  ProvenanceBadge, SectionHeadline, Kbd, Spinner. Kobalte ships compiled ESM,
  safe for the extension's webpack build.
- LayeredOptionsEditor: the shared settings surface. One tab per config layer;
  each field shows either the value set at that layer (with "reset to
  inherited"), or the inherited effective value with an "Override here"
  action. Read-only tabs (team/defaults) render values with a note.
  Text fields commit on change (blur), not per keystroke, since popup
  snapshots are polled and would recreate the DOM mid-typing.

Runtime:
- optionsStore exposes layers() (raw per-layer values) and the popup bridge
  snapshot now includes them — required to render layer tabs anywhere.

Extension popup:
- Hope UI removed (@hope-ui/solid + solid-transition-group deps dropped);
  popup now renders on @locator/ui + Tailwind.
- Settings page = LayeredOptionsEditor with tabs This origin / Extension /
  Team / Defaults. Extension tab always works — with no runtime on the page
  the popup resolves default+extension layers locally, so global defaults are
  editable offline; origin/team tabs explain they need a running page.
- Home simplified: shortcut help, current editor + provenance with a link to
  settings, disable-on-this-page. NoRuntimeView also links to settings.
- Snapshot polling dedupes by JSON so the settings DOM is not recreated every
  1.5s (would drop focus).
- popup body: fixed 260px height -> min 260 / max 580 for the taller settings.

Tests: runtime 55 pass, shared 35 pass; runtime + ui + extension builds clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Ignore packages/ui/dist like other packages

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add per-layer settings editor to the in-page options popover

The runtime options popover now embeds the shared LayeredOptionsEditor from
@locator/ui behind an "All settings by layer" disclosure: This origin
(editable), Extension / Team / Defaults (read-only with notes pointing to
where each is changed). The quick LinkOptions form with the live link
preview stays as the primary surface.

The ad-hoc debug-mode toggle is gone — it kept a local signal that shadowed
the store (stale after external changes); debugMode is now edited on the
origin tab like every other option, and the store's createEffect already
drives setDebugMode.

Runtime gains the @locator/ui dependency; tailwind content includes ui/src
so the shadow-DOM stylesheet (_generated_styles) covers the new components
(regenerated here — wrapCSS is not part of the build pipeline).

Runtime tests 55 pass; runtime + extension builds clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Migrate styling from Tailwind to Panda CSS

Add shared @locator/styled-system package (Panda preset, theme tokens,
recipes) and Park UI components; wire runtime, ui, and extension to Panda,
removing the Tailwind config.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Polish shared settings surface with connected card tabs

Build the per-layer settings UI shared by the extension popup and the
runtime overlay, and add a proper Panda "connected" tabs variant so the
active tab merges seamlessly into the content card while inactive tabs
and trailing space keep a baseline.

- Add a `connected` variant to the tabs slot recipe instead of hand-rolled
  css() overrides; the ui Tabs wrapper now only owns layout (sticky, flex).
- Drop overflowX:auto from the tablist: it forced overflow-y clipping that
  cut off the active tab's -1px baseline mask and re-exposed a line under
  the active tab. Tabs use flex:1 1 0 and fit without scrolling.
- Shared editor picker/preview, layered options editor, modifier chips,
  tooltip, collapsible, select, field, icon/brand components in @locator/ui.
- Runtime consumes the shared editor form; removed duplicated runtime forms.
- Regenerate Panda output (_generated_styles.ts, extension styled-system).
- Add UI and runtime regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Ignore generated apps/extension/styled-system

This is Panda CSS codegen output (panda.config.ts outdir: "styled-system"),
regenerated on every build by the @pandacss/dev postcss plugin. Match how
packages/styled-system/dist is handled — gitignore it and drop it from
source control so generated .mjs/.d.ts don't churn in the repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix layered settings review findings

* Finish Panda migration cleanup and add settings sync tests

Remove leftover Tailwind config and unused shadcn-style ui primitives,
move runtime styles onto Panda recipes (incl. new expand-pill recipe),
and add a server entry for the runtime package.

Add patchCodec to shared plus tests covering the shared options store,
popup synced state, and the content snapshot bridge, along with a
vitest setup for the extension and a Playwright settings spec.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants