From 60bb484ee42622bd472c7d9fcae84c16a528ad45 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Wed, 1 Jul 2026 09:05:27 +0300 Subject: [PATCH] refactor(ui): remove test-id prop APIs - Forward data-test-id attrs through rendered controls instead of exposing test-id props - Move shell chrome components into the Shell namespace - Remove internal planning docs from published VitePress docs - Add guardrails and contributor guidance for test hooks and component placement --- AGENTS.md | 14 +- lint/plugin.js | 34 +- .../docs/development/dom-css-parser-audit.md | 35 -- packages/docs/development/fig-package-plan.md | 109 ------- .../docs/development/kiwi-package-plan.md | 136 -------- packages/docs/development/package-split.md | 132 -------- packages/docs/development/ui-parity-plan.md | 298 ------------------ packages/docs/reference/dom-css-mapping.md | 4 +- packages/vue/src/index.ts | 9 +- packages/vue/src/testing/test-id.ts | 14 - src/App.vue | 2 +- src/components/AssetsPanel.vue | 2 +- src/components/CodePanel.vue | 12 +- src/components/CollabPanel/ConnectedRoom.vue | 2 +- src/components/CollabPanel/JoinRoomPrompt.vue | 2 +- .../CollabPanel/ShareOrJoinRoom.vue | 4 +- .../ColorPickerPanel/FormatControls.vue | 2 +- src/components/ColorPickerPanel/HsbFields.vue | 4 +- src/components/ColorPickerPanel/HslFields.vue | 4 +- .../ColorPickerPanel/HueAlphaSliders.vue | 4 +- .../ColorPickerPanel/OkhclFields.vue | 8 +- src/components/LayersPanel.vue | 2 +- src/components/PickerSlider.vue | 7 +- src/components/{ => Shell}/AppMenu.vue | 0 src/components/{ => Shell}/AppToast.vue | 0 src/components/Toolbar/DesktopToolbar.vue | 2 +- src/components/Toolbar/MobileToolbar.vue | 2 +- src/components/Toolbar/ToolButton.vue | 6 +- src/components/Toolbar/ToolFlyout.vue | 2 +- src/components/chat/ChatInput.vue | 2 +- .../chat/ProviderSelect/ProviderSelect.vue | 13 +- .../ProviderSelect/ProviderSelectField.vue | 5 - .../chat/ProviderSettings/ApiKeySection.vue | 3 +- .../CustomEndpointSection.vue | 6 +- .../ProviderSettings/MaxTokensSection.vue | 2 +- .../ProviderSettings/ProviderSettings.vue | 2 +- .../ProviderSettingsField.vue | 9 +- .../ProviderSettingsInput.vue | 14 +- .../ProviderSettingsKeyField.vue | 38 ++- .../StockPhotoKeysSection.vue | 6 +- src/components/chat/ProviderSetup.vue | 12 +- .../properties/AppearanceSection.vue | 2 +- .../properties/BoundVariableButton.vue | 10 +- src/components/properties/ColorStyleRow.vue | 35 +- src/components/properties/EffectsSection.vue | 2 +- .../properties/ExportScaleInput.vue | 15 +- src/components/properties/ExportSection.vue | 4 +- src/components/properties/FillSection.vue | 5 +- .../LayoutSection/LayoutSection.vue | 2 +- .../properties/LayoutSection/SizeControls.vue | 31 +- src/components/properties/PageSection.vue | 2 +- src/components/properties/PositionSection.vue | 2 +- src/components/properties/StrokeSection.vue | 5 +- .../properties/TypographySection.vue | 6 +- .../properties/VariablePickerPopover.vue | 19 +- .../properties/VariablesSection.vue | 2 +- src/components/properties/VariantSection.vue | 2 +- src/components/ui/AppComboboxInput.vue | 15 +- src/components/ui/AppGroupedSelect.vue | 10 +- src/components/ui/AppInput.vue | 8 +- src/components/ui/AppSelect.vue | 16 +- src/components/ui/AppTextButton.vue | 8 +- src/components/ui/PanelSection.vue | 8 +- src/components/ui/SegmentedControl.vue | 23 +- 64 files changed, 211 insertions(+), 985 deletions(-) delete mode 100644 packages/docs/development/dom-css-parser-audit.md delete mode 100644 packages/docs/development/fig-package-plan.md delete mode 100644 packages/docs/development/kiwi-package-plan.md delete mode 100644 packages/docs/development/package-split.md delete mode 100644 packages/docs/development/ui-parity-plan.md rename src/components/{ => Shell}/AppMenu.vue (100%) rename src/components/{ => Shell}/AppToast.vue (100%) diff --git a/AGENTS.md b/AGENTS.md index 035f3ad3c..61b6d7ba1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,7 +164,7 @@ bun run test # Playwright E2E - `AGENTS.md` (this file) — contributor/agent reference: architecture, conventions, how to release. - `packages/docs/` — VitePress site deployed at `openpencil.dev`. User guide, SDK, automation, reference, and development docs. -When adding features, update `CHANGELOG.md` (Unreleased section) and `README.md` (if user-facing). Update `AGENTS.md` when architecture or conventions change. +When adding features, update `CHANGELOG.md` (Unreleased section) and `README.md` (if user-facing). Update `AGENTS.md` when architecture or conventions change. Do not put speculative/internal implementation plans in `packages/docs/**`; VitePress docs are published. Keep temporary plans in ignored `scratch/` or distill durable public direction into the canonical roadmap. ## Commit messages @@ -358,6 +358,14 @@ Self-review checklist: ## UI +### Component structure + +- `src/components/ui/**` is the app design-system layer: reusable visual primitives, wrappers around Reka UI primitives, low-level styled controls, and UI class helpers. These files must not import app services/stores or feature panels. +- `src/components/Shell/**` is for app shell chrome and global app services rendered as components (menu bar, toast viewport, update/status chrome). Shell components may use app shell/editor stores. +- `src/components/properties/**`, `src/components/chat/**`, `src/components/LayerTree/**`, `src/components/Toolbar/**`, and similar folders are feature/domain component namespaces. Keep feature-specific controls there unless they are genuinely reusable UI primitives. +- Root-level `src/components/*.vue` is for broad editor panels/surfaces that are assembled by views or shell layout. Do not add new root-level base controls; create a domain folder or move reusable primitives to `src/components/ui/**`. +- Test hooks should be `data-test-id` attributes owned by the rendered markup or generated internally from semantic component state. Do not add `testId`, `visibilityTestId`, `triggerTestId`, or other test-id props to component APIs. + - Use reka-ui for UI components (Splitter, ContextMenu, DropdownMenu, etc.) - Vue UI styling APIs must follow the existing `:ui` / `tailwind-variants` slot pattern. Do not add one-off `fooClass`, `barClass`, `emptyActionClass`, etc. props to components; define a typed `Ui` object with named slots and merge through the local `use*UI()` helper or a `ui` prop. - Do not pass imperative setters/actions through slots as `:set-*`, `:update-*`, `:request-*`, `:toggle-*`, etc. unless the component is explicitly a renderless primitive whose whole contract is slot actions. Prefer `v-model`, emitted events, normal component props, or owned default UI. For DOM refs/focus, use VueUse (`templateRef`, `unrefElement`, `useFocus`, etc.) instead of ref callback plumbing through slots. @@ -365,7 +373,7 @@ Self-review checklist: - Editor commands share `packages/vue/src/editor/commands/registry.ts` as the canonical source for shortcut display tokens, keyboard bindings, and context-menu test IDs. Store portable shortcuts such as `MOD+D`, `MOD+SHIFT+H`, and `MOD+ALT+K`; format them with `formatShortcut()` at render time so macOS shows `⌘`/`⌥` and Windows/Linux show `Ctrl`/`Alt`. - Labels and translations must not contain shortcut text. Keep labels semantic (`Add auto layout`, `Show/Hide`) and render shortcuts from command metadata. Steiger enforces this for `packages/vue/src/i18n/messages.ts` and locale JSON files. - Canvas context-menu structure lives in `packages/vue/src/editor/menu-model/canvas.ts`. Do not hand-build command grouping in `src/components/CanvasMenu.vue`; the component should render menu entries and provide app-specific actions only when unavoidable. -- Browser and Tauri menus share `src/app/shell/menu/schema.ts` as the canonical menu model. Do not add menu items directly in `src/components/AppMenu.vue` or `desktop/src/menu.rs`. +- Browser and Tauri menus share `src/app/shell/menu/schema.ts` as the canonical menu model. Do not add menu items directly in `src/components/Shell/AppMenu.vue` or `desktop/src/menu.rs`. - Regenerate the native menu with `bun run generate:tauri-menu` after editing the shared menu schema; `desktop/generated/menu.json` is consumed by the Tauri menu builder. Tauri also runs this generator from `desktop/tauri.conf.json` via `beforeDevCommand` and `beforeBuildCommand`. - Every shared menu item with an `id` must be handled by `src/app/shell/menu/use.ts`, an editor command, or explicitly marked browser/native-only in the schema. - Tailwind 4 for styling — no inline CSS, no component-level `