feat: ship styled annotation UI controls from both packages#123
Open
w8r wants to merge 11 commits into
Open
Conversation
Promote the demo-only annotation controls into the published packages so consumers get turnkey, themeable UI instead of rebuilding toolbars, style panels, color pickers and sliders by hand. - core: new framework-agnostic `@linkurious/ogma-annotations/ui` subpath exporting the `AnnotationPanel`, shared config, color reducer, inline SVG icon set, and the `attachPanelVisibility` state machine. Styles ship as `/ui/styles.css`, themeable via `--oa-*` CSS variables. - react: new `@linkurious/ogma-annotations-react/ui` subpath with `AnnotationPanelController`, `AddMenu`, `ViewControls`, the field controllers, the `useAnnotationPanel` hook and an inline-SVG `Icon`. Reuses the shared core logic; no icon font / lucide-react runtime dep. - Logic that was duplicated between the vanilla and React panels (config, recent-colors, visibility state machine, stylesheet) now lives once in core. - Build: multi-entry libs emit separate `index`/`ui` bundles + types; UI is fully opt-in so the headless main entries stay lean. `vanilla-colorful` becomes a runtime dependency of both packages. - Demos now consume the published `/ui` API; old duplicated demo components removed. - Adds unit tests for the shared color reducer, icons and visibility machine.
There was a problem hiding this comment.
Pull request overview
This PR promotes the previously demo-only, styled annotation UI (panel + toolbar controls) into published, opt-in /ui subpath entries for both @linkurious/ogma-annotations (vanilla/core) and @linkurious/ogma-annotations-react (React), while centralizing duplicated UI logic (icons, color helpers, config constants, and panel-visibility state machine) in core so React can consume it.
Changes:
- Added a new core
/uientry with shared UI building blocks (styles, icons, recent-colors helpers, and a panel-visibility state machine) and updated the vanillaAnnotationPanelto consume them. - Added a new React
/uientry exporting styled UI components and controllers, including an inline-SVGIconcomponent and aggregated CSS (@importfrom core + React toolbar styles). - Updated build/package exports for multi-entry ESM+CJS outputs; rewired demos to use published
/uiAPIs; adjusted/added tests.
Reviewed changes
Copilot reviewed 36 out of 38 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react/web/src/tooltip.css | Deleted demo-only tooltip CSS (moved into published React UI CSS). |
| packages/react/web/src/components/ViewControls.css | Deleted demo-only ViewControls CSS (moved into published React UI CSS). |
| packages/react/web/src/components/Controls.tsx | Demo now imports AddMenu/ViewControls from published React /ui entry and imports /ui CSS. |
| packages/react/web/src/components/AnnotationPanelController.tsx | Deleted demo-local controller (replaced by published React /ui controller). |
| packages/react/web/src/components/AnnotationPanel.css | Deleted demo-local panel CSS (replaced by shared core /ui stylesheet). |
| packages/react/web/src/components/AddMenu.css | Deleted demo-local AddMenu CSS (replaced by published React UI stylesheet). |
| packages/react/web/src/App.tsx | Demo now imports AnnotationPanelController from published React /ui entry. |
| packages/react/vite.config.ts | React package build updated to multi-entry (index + ui), ESM+CJS formats, updated externals. |
| packages/react/src/ui/ViewControls.tsx | Switched icons to shared inline SVG icon set; removed demo CSS imports. |
| packages/react/src/ui/toolbar.css | New React UI toolbar + view-controls + tooltip styling. |
| packages/react/src/ui/styles.css | New React UI stylesheet that imports core panel styles + React toolbar styles. |
| packages/react/src/ui/index.ts | New React /ui entry exporting styled UI components/controllers and importing CSS side-effects. |
| packages/react/src/ui/Icon.tsx | New React inline-SVG icon component backed by core ICON_PATHS. |
| packages/react/src/ui/controllers/SliderController.tsx | Tightened property typing and updated context import path. |
| packages/react/src/ui/controllers/LineTypeController.tsx | Consumes shared LINE_TYPES + Icon rendering. |
| packages/react/src/ui/controllers/index.ts | New barrel export for the 6 field controllers. |
| packages/react/src/ui/controllers/FontController.tsx | Consumes shared FONTS + Icon rendering. |
| packages/react/src/ui/controllers/ExtremityController.tsx | Consumes shared EXTREMITY_OPTIONS + Icon rendering; minor refactors. |
| packages/react/src/ui/controllers/ColorController.tsx | Uses shared recent-colors reducer/helpers; syncs recent colors on selection changes. |
| packages/react/src/ui/controllers/BackgroundController.tsx | Consumes shared background swatches; adds configurable section title. |
| packages/react/src/ui/AnnotationPanelController.tsx | New React controller/hook using shared attachPanelVisibility. |
| packages/react/src/ui/AnnotationPanel.tsx | Updates prop types and annotation-mode logic (incl. comments); removes demo CSS import. |
| packages/react/src/ui/AddMenu.tsx | Replaces lucide-react icons with shared inline SVG Icon; optional export buttons. |
| packages/react/package.json | Adds /ui exports + CSS export; adds vanilla-colorful runtime dependency. |
| packages/core/web/main.ts | Demo now imports AnnotationPanel and CSS from published core /ui entry. |
| packages/core/vite.config.ts | Core package build updated to multi-entry (index + ui), ESM+CJS formats, updated externals. |
| packages/core/test/unit/ui.test.ts | New unit tests for shared UI helpers (recent-colors, icons, visibility machine). |
| packages/core/test/e2e/vitest.config.mts | Removes retry policy from browser-driven e2e test config. |
| packages/core/test/e2e/comment.test.ts | Skips multiple comment e2e tests and removes a regression test. |
| packages/core/src/ui/styles.css | Promotes panel stylesheet to canonical, themeable --oa-* tokens and icon selector updates. |
| packages/core/src/ui/panelVisibility.ts | New shared framework-agnostic panel visibility state machine. |
| packages/core/src/ui/index.ts | New core /ui entry exporting panel and shared UI building blocks. |
| packages/core/src/ui/icons.ts | New shared inline SVG icon path set + helpers. |
| packages/core/src/ui/config.ts | New shared UI config constants (backgrounds/fonts/extremities/line types). |
| packages/core/src/ui/color.ts | New shared recent-colors reducer/state + rgba serializer. |
| packages/core/src/ui/AnnotationPanel.ts | Refactored vanilla panel to consume shared config/icons/color + new visibility machine; mounts its own DOM. |
| packages/core/package.json | Adds /ui exports + CSS export; moves vanilla-colorful to runtime deps; adds postbuild copy for UI stylesheet. |
| package-lock.json | Lockfile updates (incl. dependency version resolution changes). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
26
to
28
| rollupOptions: { | ||
| external: ["@linkurious/ogma"], | ||
| output: { | ||
| globals: { | ||
| "@linkurious/ogma": "Ogma" | ||
| } | ||
| } | ||
| external: ["@linkurious/ogma", "vanilla-colorful"] | ||
| }, |
Comment on lines
+57
to
60
| it.skip("should create comment on void", async () => { | ||
| const pos = await session.page.evaluate(() => { | ||
| editor.enableCommentDrawing({ offsetX: 50, offsetY: -50 }); | ||
| // Far from any node or edge (off-diagonal from the n1-n2 edge) |
Comment on lines
3
to
6
| export default defineConfig({ | ||
| test: { | ||
| include: ["test/e2e/**/*.test.ts"], | ||
| // Browser-driven e2e tests start a Playwright/WebSocket session; retry | ||
| // once to absorb transient connection/timing flakiness under CI load. | ||
| retry: 2 | ||
| include: ["test/e2e/**/*.test.ts"] | ||
| } |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Core's tsconfig uses moduleResolution "Node", which ignores the package.json exports map, so "@linkurious/ogma-annotations/ui" could not be resolved in the editor or the web demo. Add a paths mapping to the live source. Does not affect the library build (Vite/Rollup resolves via exports).
Add a focused page per package for the new opt-in UI: - react/ui-components/ready-made: AnnotationPanelController, AddMenu, ViewControls, the field controllers, Icon, CSS import and theming. - typescript/ui-components/style-panel: the vanilla AnnotationPanel, its options/methods, theming, and the exported building blocks. Register both in the VitePress sidebar. Existing 'build your own' pages are left as the advanced path.
Two runtime failures surfaced when consuming the built /ui entry (as the demo now does) rather than source: 1. "the name rgba-color-picker has already been used" — vanilla-colorful's rgba-color-picker.js calls customElements.define() unconditionally, so it throws when reached through two resolution paths. Add a guarded createRgbaColorPicker() in core that imports the non-defining RgbaBase entrypoint and registers behind customElements.get(). Both the vanilla panel and the React ColorController use it. Externalize all vanilla-colorful subpaths in both lib builds. 2. "Cannot destructure property 'editor' ... undefined" — the React /ui components read the AnnotationsContext, but bundling /ui separately gave it its own context instance. Import useAnnotationsContext from the package main entry (externalized) so there is a single shared context. Point the demo's provider/context imports at the package too, mirroring a real consumer. Verified in a headless browser: demo loads with zero console errors and the style panel appears on selection.
Embed image references (with placeholder PNGs) in the React and TypeScript UI-component pages, and a README listing the expected shots. Replace the placeholders with real screenshots.
The /ui sources import the package's own main entry (for the shared React context) and core's /ui subpath. tsc runs before vite emits dist, so on a clean checkout (CI) it could not resolve @linkurious/ogma-annotations-react or @linkurious/ogma-annotations/ui — it only worked locally because a stale dist/ was present. Map both to source via tsconfig paths for typecheck; the bundler still externalizes them at runtime so consumers share one instance.
Two issues made the panel (text especially) appear inconsistently: 1. The visibility state machine only revealed the panel on a follow-up 'click'/'dragend' event after 'select'. Those don't always fire — programmatic selection emits only 'select', and a text annotation's DOM overlay can swallow the click — so the panel never showed. Reveal on a short timer after 'select' instead; a drag's 'dragstart' cancels it to avoid a flicker, and 'click'/'dragend' still pre-empt it for snappiness. Removes the now-redundant 200ms delay in the vanilla panel's show(). 2. The React AnnotationPanel derived its render 'mode' via useState+useEffect, which lagged the annotation prop by a render; during that window the mode and annotation guards disagreed and nothing rendered. Derive the branch directly from the annotation instead. Updates the panelVisibility unit tests (fake timers) for the new behavior.
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.
Why
Both packages are currently headless — every consumer who wants a real editor has to rebuild the same toolbar, style panel, color picker and sliders by hand. A full set of those controls already existed, but only in the demo (
web/) trees, unbuilt and unpublished. This promotes them into the published packages as styled, themeable components, authored once in core and thin-wrapped in React to avoid duplication.What consumers get
Vanilla /
@linkurious/ogma-annotations:React /
@linkurious/ogma-annotations-react:Also exported: the 6 field controllers, the
useAnnotationPanel()hook, and an inline-SVGIcon.Design
/uisubpath on each package with opt-in CSS — the headless main entries stay lean (verified: neither mainindex.mjsreferencesvanilla-colorful, the panel, icons or CSS).src/ui/: config constants, recent-colors reducer, inline SVG icon set, and the panel-visibility state machine (previously copied byte-for-byte between the vanilla constructor and the React controller). React consumes these.lucide-reactruntime dependency for consumers.--oa-*CSS variables; defaults preserve the current look); React@imports it and adds toolbar styles./uiAPI (proves the surface is usable); old duplicated demo components deleted.Notes / behavior changes
vanilla-colorfulis now a runtime dependency of both packages (was a devDep)../umdexport still points at the CJSdist/index.js, sorequire()consumers are unaffected, but a<script>-tag global build is no longer produced. Can add a separate single-entry UMD build for headless core if anyone relies on that.Verification
dist/ui.{mjs,js}, CSS, and types for both entries)./uiAPI.Out of scope
Accessibility/keyboard nav, the export popups, and re-authoring leaf widgets as framework-agnostic custom elements (deferred).