JSPM

@viscalyx/developer-mode-core

0.2.2
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 165
  • Score
    100M100P100Q82128F
  • License MIT

Framework-agnostic developer mode utilities and marker helpers

Package Exports

  • @viscalyx/developer-mode-core
  • @viscalyx/developer-mode-core/noop
  • @viscalyx/developer-mode-core/package.json

Readme

@viscalyx/developer-mode-core

Framework-agnostic Developer Mode utilities for marker-backed UI discovery, stable naming, copy payload generation, and viewport scanning.

Overview

@viscalyx/developer-mode-core is the low-level package behind the Developer Mode overlay. It does not render any UI. Instead, it provides the shared contract that host applications and UI runtimes use to:

  • emit curated data-developer-mode-* markers
  • normalize marker text and values
  • scan visible DOM targets
  • resolve the best target under the pointer
  • build deterministic chip labels and copy payloads
  • detect the Developer Mode keyboard shortcut

Use this package when you want a reusable naming layer that can be consumed by an overlay, inspector, test helper, or custom debugging tool.

When To Use This Package

Use @viscalyx/developer-mode-core when you need one or more of these capabilities:

  • a stable marker API for important UI surfaces
  • deterministic copy text such as requirements table > column header: requirement id
  • a consistent keyboard shortcut contract for toggling developer tooling
  • DOM scanning helpers that prefer curated markers but can fall back to semantic roles and stable labels
  • a no-op marker helper for production builds that should not emit marker attributes

If you also want a ready-made React overlay, use this package together with @viscalyx/developer-mode-react.

Installation

npm install --save-dev @viscalyx/developer-mode-core

Current Repo Usage

In this repository, the package is currently consumed as a local devDependency:

"@viscalyx/developer-mode-core": "file:packages/developer-mode-core"

App code does not import the package directly from every component. Instead, it routes marker creation through a small host adapter:

That pattern is recommended for future consumers too, because it gives the host application one place to centralize naming conventions, helper wrappers, and future no-op behavior.

Quick Start

1. Mark important UI surfaces

import { devMarker } from '@viscalyx/developer-mode-core'

export function RequirementsHeader() {
  return (
    <button
      {...devMarker({
        context: 'requirements table',
        name: 'column header',
        value: 'requirement id',
        priority: 500,
      })}
      type="button"
    >
      Requirement ID
    </button>
  )
}

When Developer Mode is enabled, devMarker(...) emits curated data-developer-mode-* attributes. When the package is aliased to its ./noop entrypoint, the same call returns {} so production HTML stays clean.

2. Resolve visible targets

import {
  findDeveloperModeTargetAt,
  scanVisibleDeveloperModeTargets,
} from '@viscalyx/developer-mode-core'

const hoveredTarget = findDeveloperModeTargetAt(event.target as HTMLElement)
const visibleTargets = scanVisibleDeveloperModeTargets(document.body)

3. Build stable copy text

import { buildDeveloperModeCopyText } from '@viscalyx/developer-mode-core'

const payload = buildDeveloperModeCopyText({
  context: 'requirements table',
  name: 'column header',
  value: 'requirement id',
})

// "requirements table > column header: requirement id"

Marker API

The main authoring API is devMarker(...).

devMarker({
  name: 'column header',
  context: 'requirements table',
  value: 'requirement id',
  priority: 500,
})

Supported input fields:

  • name: required canonical English label
  • context: optional English parent context
  • value: optional English or runtime value
  • priority: optional numeric override used to win collisions

When enabled, the helper emits:

  • data-developer-mode-name
  • data-developer-mode-context
  • data-developer-mode-value
  • data-developer-mode-priority

The package also exports:

  • noopDevMarker(): always returns {}
  • normalizeDeveloperModeText(value): collapses whitespace and removes empty strings

Copy Text Fallback Ladder

buildDeveloperModeCopyText(...) produces a deterministic string by picking the first matching format from this ladder, based on which fields are populated:

  1. context > name: value — when context, name, and value are all present.
  2. context > name — when context and name are present but value is not.
  3. name: value — when name and value are present but context is not.
  4. name — when only name is present.

This ordering is stable across versions. Host applications can rely on it when reusing copied payloads in prompts, support notes, or test fixtures.

API Overview

This package intentionally exposes a small practical surface:

  • devMarker(...) and noopDevMarker() for DOM authoring
  • buildDeveloperModeCopyText(...) for deterministic copied references
  • buildDeveloperModeChipLabel(...) for compact overlay labels
  • matchesDeveloperModeShortcut(...) plus shortcut constants for keyboard activation
  • isEditableTarget(...) to ignore toggles inside inputs and editable regions
  • findDeveloperModeTargetAt(...) to resolve the best target from a hovered DOM element
  • scanVisibleDeveloperModeTargets(...) to scan the viewport for visible targets
  • shared types such as DeveloperModeDescriptor, DeveloperModeTarget, and DeveloperModeMarkerInput

Scanning And Fallback Behavior

The scanner prefers curated markers first, then falls back to a bounded set of generic heuristics.

Priority order:

  1. explicit data-developer-mode-* markers
  2. known product hooks such as data-floating-action-rail
  3. semantic roles such as dialog, tab, tabpanel, and navigation
  4. aria-label and title
  5. stable visible text
  6. data-testid

The scanner only returns targets that are currently visible in the viewport and skips:

  • hidden or aria-hidden nodes
  • zero-sized elements
  • offscreen elements
  • the Developer Mode overlay itself

Shortcut Contract

The package exports the shared shortcut constants:

  • DEVELOPER_MODE_SHORTCUT_LABEL: Mod+Alt+Shift+H
  • DEVELOPER_MODE_SHORTCUT_KEY: h
  • DEVELOPER_MODE_SHORTCUT_CODE: KeyH

Use matchesDeveloperModeShortcut(...) instead of comparing raw key values yourself. It accepts either the physical KeyH code or a matching lowercase key, which keeps the shortcut stable even when modifier keys alter the typed character on some keyboard layouts.

No-Op And Production Exclusion

The package exposes a ./noop entrypoint for builds that should keep the call sites but remove the marker output:

import { devMarker } from '@viscalyx/developer-mode-core/noop'

In practice, most applications should not import ./noop directly from components. Instead, configure a build-time alias so the main package resolves to ./noop in production or other non-debug builds.

In this repository:

  • local development uses the real package
  • non-development builds alias the package to packages/developer-mode-core/src/noop.ts unless ENABLE_DEVELOPER_MODE=true

See Developer Mode Overlay for the repo-specific build wiring.

Used Together With @viscalyx/developer-mode-react

@viscalyx/developer-mode-core provides the contract and scanning logic. @viscalyx/developer-mode-react provides the visible overlay and interaction layer.

Typical division of responsibility:

  • core:
    • marker helpers
    • target discovery
    • copy text and chip label formatting
    • shortcut matching
  • react:
    • provider lifecycle
    • pointer tracking
    • portal rendering
    • copy toast and overlay chip UI

Minimal combined example:

import { devMarker } from '@viscalyx/developer-mode-core'
import DeveloperModeProvider from '@viscalyx/developer-mode-react'

export function AppShell({ children }: { children: React.ReactNode }) {
  return (
    <DeveloperModeProvider
      labels={{
        badge: 'Developer Mode',
        copied: 'Copied',
        copyFailed: 'Copy failed',
      }}
    >
      <main {...devMarker({ name: 'main content' })}>{children}</main>
    </DeveloperModeProvider>
  )
}

For a fuller React integration guide, see packages/developer-mode-react/README.md.

Notes For Host Applications

  • Keep curated labels in English, even if the product UI is localized.
  • Prefer a host-side adapter such as lib/developer-mode-markers.ts so app code does not hardcode package-specific policy everywhere.
  • Use curated markers for important product surfaces first, then rely on fallback scanning only for generic coverage.
  • Keep copied payloads deterministic. A stable context > name: value format makes prompts and support notes much easier to reuse.
  • Treat priority as an escape hatch. Use it only when two nearby candidates would otherwise compete for the same overlay region.