wenay-react2 1.0.49 → 1.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +14 -14
  2. package/doc/EXAMPLE_USAGE.md +48 -0
  3. package/doc/PROJECT_FUNCTIONALITY.md +9 -0
  4. package/doc/PROJECT_RULES.md +27 -27
  5. package/doc/WENAY_REACT2_RENAMES.md +170 -170
  6. package/doc/changes/v1.0.41.md +35 -35
  7. package/doc/changes/v1.0.42.md +26 -26
  8. package/doc/changes/v1.0.43.md +10 -10
  9. package/doc/changes/v1.0.44.md +14 -14
  10. package/doc/changes/v1.0.45.md +8 -8
  11. package/doc/changes/v1.0.46.md +11 -11
  12. package/doc/changes/v1.0.47.md +9 -9
  13. package/doc/changes/v1.0.48.md +8 -8
  14. package/doc/changes/v1.0.49.md +7 -7
  15. package/doc/changes/v1.0.50.md +7 -0
  16. package/doc/examples/README.md +1 -1
  17. package/doc/examples/conference-client.html +34 -34
  18. package/doc/examples/conference-client.ts +212 -212
  19. package/doc/examples/conference-server.mjs +150 -150
  20. package/doc/examples/peer-call-media.tsx +7 -7
  21. package/doc/examples/stand.tsx +5 -5
  22. package/doc/native.md +37 -37
  23. package/doc/progress/README.md +13 -13
  24. package/doc/progress/architecture-fix-queue.md +74 -74
  25. package/doc/progress/column-state-present-gate.md +28 -28
  26. package/doc/progress/common2-adoption-1.0.73.md +28 -28
  27. package/doc/progress/common2-adoption-1.0.74.md +24 -24
  28. package/doc/progress/hook-controller-opportunities.md +363 -363
  29. package/doc/progress/hook-extraction-audit.md +195 -195
  30. package/doc/progress/public-surface-normalization.md +351 -351
  31. package/doc/progress/qa-stand-walkthrough-2026-07-12.md +62 -62
  32. package/doc/progress/stand-as-examples-audit.md +20 -20
  33. package/doc/progress/style-system-normalization.md +121 -121
  34. package/doc/target/README.md +32 -32
  35. package/doc/wenay-react2-rare.md +3 -0
  36. package/doc/wenay-react2.md +1 -1
  37. package/lib/common/src/hooks/useReplay.js +6 -2
  38. package/lib/common/testUseReact/qa.js +2 -2
  39. package/lib/common/testUseReact/replayVideo.d.ts +5 -0
  40. package/lib/common/testUseReact/replayVideo.js +98 -1
  41. package/lib/style/menuRight.css +19 -19
  42. package/lib/style/style.css +23 -23
  43. package/lib/style/tokens.css +184 -184
  44. package/package.json +54 -54
  45. package/doc/changes/v1.0.35.md +0 -26
  46. package/doc/changes/v1.0.37.md +0 -13
  47. package/doc/changes/v1.0.38.md +0 -48
  48. package/doc/changes/v1.0.39.md +0 -35
  49. package/doc/changes/v1.0.40.md +0 -15
@@ -1,62 +1,62 @@
1
- # QA stand walkthrough — 2026-07-12
2
-
3
- Полный автоматизированный проход всех 43 карточек стенда (28 active + 15 archive) в браузере
4
- после восстановления окружения с нуля. Итог: **все проверяемые контракты подтверждены,
5
- 0 ошибок в консоли за весь проход**; найденные дефекты стенда исправлены (см. ниже).
6
-
7
- ## Окружение (восстановлено с нуля)
8
-
9
- - `pnpm install` (pnpm 9, lockfile 9.0). **Важно:** установка должна идти под Node ≥22.12 —
10
- под Node 21 pnpm молча пропускает `@rolldown/binding-win32-x64-msvc` (engines-фильтр),
11
- и vite 8 не стартует («Cannot find native binding»).
12
- - Системный Node 21.6 (EOL) не подходит для Vite 8: портативный Node 22.23.1 лежит в
13
- `~/.tools/node-v22.23.1-win-x64`, стенд запускается обёрткой `~/.tools/vite-node22.cmd`
14
- (прописана в `.claude/launch.json`).
15
- - `typescript ^5` добавлен в devDependencies (раньше жил только глобально). TS 7 не брать:
16
- ts-jest требует `<7`, tsconfig использует удалённый в TS7 `moduleResolution: node10` —
17
- миграция записана как кандидат в breaking-проход.
18
- - Проверки: tsc qa-check ✅, Jest 23 suites / 78 tests ✅, build ✅.
19
-
20
- ## Результаты по карточкам
21
-
22
- Автоматически подтверждены (клики/жесты синтетикой, чтение DOM/модели):
23
- 1, 3, 4, 5, 7 (sync+t33), 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 2, 20 (поиск/RU-раскладка/
24
- двухступенчатый Escape/реестр), 21 (+F5-персист), 22, 23 (A–E), 24, 25 (+F5, reset), 26, 27,
25
- 28 (двусторонний контракт), 29, 30 (presentGate 4 режима), 31, 32, 33, 34, 35, 40, 41, 42.
26
- Медиа 38/39/43/44/45: deny-путь чистый (idle→denied без крэша), звонок 45 без медиа проходит
27
- ringing→active→idle.
28
-
29
- ## Чек-лист ручной приёмки (нужны глаза/устройства)
30
-
31
- - **6** — амплитуда LOD на зуме (визуально); **23/34** — плавность видео.
32
- - **19** — fixed-parent select при 150/240px (метки на RO+rAF пайплайне).
33
- - **20** — драг разделителя дерева, history-дропдаун; **25/30/31** — drag-reorder строк
34
- настроек и HOLD-превью середины жеста; **26/27** — совпадение превью и коммита глазами.
35
- - **28** — драг заголовков ag-grid и resize (нативный dragService не берётся синтетикой).
36
- - **29/32** — live-замена поля при медленном драге точки + палец-лейбл.
37
- - **9** — всплывающая нотификация (~2 c) и её выключатель.
38
- - **38/39/43/44/45** — реальная камера/микрофон: живое видео на канвасе, эхо голоса,
39
- заморозка счётчиков при ACL-revoke, hidden-tab.
40
-
41
- ## Исправления по итогам прохода
42
-
43
- - qa.tsx: карточка 14 «click clear»→«reset via API»; карточка 29 — снят недостижимый
44
- «Max 4 dots» (демо даёт max=8 на 8 колонок); карточка 38 — ожидание без фантомного
45
- «requesting»; карточка 2 — `onCLickClose`→`onClickClose` (2 места) и обновлена note про
46
- исторический xxx-спам.
47
- - demo/peerMedia.tsx (карточка 45): аудио теперь включается по документированным шагам —
48
- намерение enable запоминается и применяется к плееру, создаваемому после accept.
49
- - logsController.ts: подписи `minVarLogs`/`minVarMessage` были перепутаны местами
50
- (minVarLogs фильтрует таблицу — logs.tsx:149; minVarMessage гейтит нотификации —
51
- logs.tsx:294). Поменяны только name-строки, ключи/семантика не тронуты.
52
-
53
- ## Заметки для будущей автоматизации стенда
54
-
55
- - Панель Claude-браузера не рисует кадры: CSS-переходы замирают → визуальные позиции строк
56
- ag-grid читать по `row-index`/`aria-rowcount`/inline transform, НЕ по getBoundingClientRect.
57
- - ag-grid v35: клик по ячейке требует pointer-событий; заголовки/колонки виртуализуются
58
- горизонтально (скроллить вьюпорт перед чтением).
59
- - ColumnDots: синтетические PointerEvent работают после no-op патча
60
- `Element.prototype.setPointerCapture`.
61
- - useDraggable/useReorder: после mousedown дать тик (~50 мс) на подписку document-слушателей,
62
- mousemove слать с `buttons:1`.
1
+ # QA stand walkthrough — 2026-07-12
2
+
3
+ Полный автоматизированный проход всех 43 карточек стенда (28 active + 15 archive) в браузере
4
+ после восстановления окружения с нуля. Итог: **все проверяемые контракты подтверждены,
5
+ 0 ошибок в консоли за весь проход**; найденные дефекты стенда исправлены (см. ниже).
6
+
7
+ ## Окружение (восстановлено с нуля)
8
+
9
+ - `pnpm install` (pnpm 9, lockfile 9.0). **Важно:** установка должна идти под Node ≥22.12 —
10
+ под Node 21 pnpm молча пропускает `@rolldown/binding-win32-x64-msvc` (engines-фильтр),
11
+ и vite 8 не стартует («Cannot find native binding»).
12
+ - Системный Node 21.6 (EOL) не подходит для Vite 8: портативный Node 22.23.1 лежит в
13
+ `~/.tools/node-v22.23.1-win-x64`, стенд запускается обёрткой `~/.tools/vite-node22.cmd`
14
+ (прописана в `.claude/launch.json`).
15
+ - `typescript ^5` добавлен в devDependencies (раньше жил только глобально). TS 7 не брать:
16
+ ts-jest требует `<7`, tsconfig использует удалённый в TS7 `moduleResolution: node10` —
17
+ миграция записана как кандидат в breaking-проход.
18
+ - Проверки: tsc qa-check ✅, Jest 23 suites / 78 tests ✅, build ✅.
19
+
20
+ ## Результаты по карточкам
21
+
22
+ Автоматически подтверждены (клики/жесты синтетикой, чтение DOM/модели):
23
+ 1, 3, 4, 5, 7 (sync+t33), 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 2, 20 (поиск/RU-раскладка/
24
+ двухступенчатый Escape/реестр), 21 (+F5-персист), 22, 23 (A–E), 24, 25 (+F5, reset), 26, 27,
25
+ 28 (двусторонний контракт), 29, 30 (presentGate 4 режима), 31, 32, 33, 34, 35, 40, 41, 42.
26
+ Медиа 38/39/43/44/45: deny-путь чистый (idle→denied без крэша), звонок 45 без медиа проходит
27
+ ringing→active→idle.
28
+
29
+ ## Чек-лист ручной приёмки (нужны глаза/устройства)
30
+
31
+ - **6** — амплитуда LOD на зуме (визуально); **23/34** — плавность видео.
32
+ - **19** — fixed-parent select при 150/240px (метки на RO+rAF пайплайне).
33
+ - **20** — драг разделителя дерева, history-дропдаун; **25/30/31** — drag-reorder строк
34
+ настроек и HOLD-превью середины жеста; **26/27** — совпадение превью и коммита глазами.
35
+ - **28** — драг заголовков ag-grid и resize (нативный dragService не берётся синтетикой).
36
+ - **29/32** — live-замена поля при медленном драге точки + палец-лейбл.
37
+ - **9** — всплывающая нотификация (~2 c) и её выключатель.
38
+ - **38/39/43/44/45** — реальная камера/микрофон: живое видео на канвасе, эхо голоса,
39
+ заморозка счётчиков при ACL-revoke, hidden-tab.
40
+
41
+ ## Исправления по итогам прохода
42
+
43
+ - qa.tsx: карточка 14 «click clear»→«reset via API»; карточка 29 — снят недостижимый
44
+ «Max 4 dots» (демо даёт max=8 на 8 колонок); карточка 38 — ожидание без фантомного
45
+ «requesting»; карточка 2 — `onCLickClose`→`onClickClose` (2 места) и обновлена note про
46
+ исторический xxx-спам.
47
+ - demo/peerMedia.tsx (карточка 45): аудио теперь включается по документированным шагам —
48
+ намерение enable запоминается и применяется к плееру, создаваемому после accept.
49
+ - logsController.ts: подписи `minVarLogs`/`minVarMessage` были перепутаны местами
50
+ (minVarLogs фильтрует таблицу — logs.tsx:149; minVarMessage гейтит нотификации —
51
+ logs.tsx:294). Поменяны только name-строки, ключи/семантика не тронуты.
52
+
53
+ ## Заметки для будущей автоматизации стенда
54
+
55
+ - Панель Claude-браузера не рисует кадры: CSS-переходы замирают → визуальные позиции строк
56
+ ag-grid читать по `row-index`/`aria-rowcount`/inline transform, НЕ по getBoundingClientRect.
57
+ - ag-grid v35: клик по ячейке требует pointer-событий; заголовки/колонки виртуализуются
58
+ горизонтально (скроллить вьюпорт перед чтением).
59
+ - ColumnDots: синтетические PointerEvent работают после no-op патча
60
+ `Element.prototype.setPointerCapture`.
61
+ - useDraggable/useReorder: после mousedown дать тик (~50 мс) на подписку document-слушателей,
62
+ mousemove слать с `buttons:1`.
@@ -1,22 +1,22 @@
1
- # Stand as examples — audit
2
-
3
- ## Current shape
4
-
5
- - `src/common/testUseReact/qa.tsx` owns 44 hand-written cards and the component implementations are mostly in the same file.
6
- - The board has only Active/Archive separation. It does not declare whether a card is canonical consumer guidance or internal regression/compat coverage.
7
- - `doc/examples/peer-call-media.tsx` is shipped, but card 41–44 currently use a parallel implementation.
8
-
9
- ## Decision
10
-
11
- Turn the stand into a renderer/acceptance layer over a small set of canonical demo modules. Ship those modules in `demo/`; keep isolated repros and compat examples in QA/regression only. Use a manifest per card to link source demo, automated test and manual verification.
12
-
13
- ## First migration
14
-
15
- Extract Media/Peer calls, presence, camera relay and microphone relay. The QA cards must import the same component that is shipped in the package. No new transport/ACL code belongs in React.
16
- ## Batch 1 complete — Media/Peer
17
-
18
- - Extracted cards 41–44 into `src/common/demo/peerMedia.tsx`.
19
- - QA imports those exact components; package exports `wenay-react2/demo/peer-media`.
20
- - `doc/examples/peer-call-media.tsx` re-exports the public demo entrypoint.
1
+ # Stand as examples — audit
2
+
3
+ ## Current shape
4
+
5
+ - `src/common/testUseReact/qa.tsx` owns 44 hand-written cards and the component implementations are mostly in the same file.
6
+ - The board has only Active/Archive separation. It does not declare whether a card is canonical consumer guidance or internal regression/compat coverage.
7
+ - `doc/examples/peer-call-media.tsx` is shipped, but card 41–44 currently use a parallel implementation.
8
+
9
+ ## Decision
10
+
11
+ Turn the stand into a renderer/acceptance layer over a small set of canonical demo modules. Ship those modules in `demo/`; keep isolated repros and compat examples in QA/regression only. Use a manifest per card to link source demo, automated test and manual verification.
12
+
13
+ ## First migration
14
+
15
+ Extract Media/Peer calls, presence, camera relay and microphone relay. The QA cards must import the same component that is shipped in the package. No new transport/ACL code belongs in React.
16
+ ## Batch 1 complete — Media/Peer
17
+
18
+ - Extracted cards 41–44 into `src/common/demo/peerMedia.tsx`.
19
+ - QA imports those exact components; package exports `wenay-react2/demo/peer-media`.
20
+ - `doc/examples/peer-call-media.tsx` re-exports the public demo entrypoint.
21
21
  - Remaining batches: Replay, then toolbar/columnState/grid; archive stays internal.
22
22
  - Verification: qa-check TypeScript, full Jest (21 suites / 71 tests), package build and Vite stand cards 41–44 all pass. The package is browser-oriented; direct Node require is not a supported validation surface for its extensionless ESM build.
@@ -1,121 +1,121 @@
1
- # Style system normalization
2
-
3
- Status: done/released (v1.0.38, v1.0.39, v1.0.41); default inventory and column-state scoped token fixes implemented and shipped.
4
-
5
- ## Source
6
-
7
- User clarification: compatibility can be an aggressive migration when it is
8
- clearly recorded in changelog, but default styles are dangerous to remove.
9
- If default styles disappear, the project can become visually broken even when
10
- the TypeScript/API migration is understandable.
11
-
12
- ## Standard
13
-
14
- - Shared primitives must keep a usable default visual style.
15
- - A default style may be changed, but not silently removed.
16
- - Removing/replacing a default class requires a replacement class/token path,
17
- changelog entry, and migration note.
18
- - New shared visual rules should use CSS custom properties first.
19
- - Runtime geometry may stay inline when it is state-derived, but color, spacing,
20
- border, shadow, font, and hover/active states should move to classes/tokens.
21
- - Apps may override variables; primitives should not require apps to copy a full
22
- CSS block to remain usable.
23
-
24
- ## Token direction
25
-
26
- Current prefixes are a good start:
27
-
28
- - `--color-*`
29
- - `--menu-*`
30
- - `--wnd-*`
31
- - `--dlg-*`
32
- - `--tb-*`
33
- - `--logs-*`
34
- - `--cols-menu-*` for compact `ColumnsMenu/MenuStrip` visuals.
35
- - `--cols-dots-*` for `ColumnDots` visuals.
36
- - `--cols-card-*` for `CardList` visuals.
37
-
38
- Likely next prefixes:
39
-
40
- - `--cols-*` remains a family prefix; concrete prefixes now use `--cols-menu-*`, `--cols-dots-*`, and `--cols-card-*`.
41
- - `--input-*` for generic input/panel defaults if they stay public.
42
- - `--param-*` for `ParamsEditor` if it remains a shared primitive.
43
-
44
- ## First audit candidates
45
-
46
- - `src/style/style.css`: old button/menu classes, `FloatingWindow`, `SettingsDialog`, `Toolbar`, `ColumnDots/CardList`, and raw hover colors.
47
- - `src/style/menuRight.css`: right-menu visual contract and default state styles.
48
- - `src/common/src/grid/columnState/*`: finish deciding whether mobile/card
49
- visuals need `--cols-*` tokens.
50
- - `src/common/src/components/ParamsEditor.tsx`: move reusable editor visuals
51
- out of component-owned inline styles if the API remains public.
52
- - `src/common/src/components/Input.tsx`: decide whether old input panels are
53
- compatibility-only or need a proper tokenized default.
54
-
55
- ## Acceptance
56
-
57
- - Default visual contract documented per public primitive group.
58
- - Token prefixes chosen before broad style rewrites.
59
- - No removal of default classes without replacement and changelog.
60
- - Scoped visual QA cards checked before and after style migration.
61
- ## 2026-07-09 default style contract inventory
62
-
63
- Source of truth:
64
-
65
- - CSS tokens: `src/style/tokens.css`.
66
- - TS mirror for inline styles/theme builders: `src/common/src/styles/tokens.ts`.
67
- - Shared runtime CSS: `src/style/style.css` and `src/style/menuRight.css`.
68
- - Generated `dist/lib/style/*` is build output, not the edit target.
69
-
70
- Public/default visual contracts:
71
-
72
- - `Menu` / `MenuR` / mouse context menu: legacy `.MenuR`, `.toButton`, `.toButtonA` classes remain; colors/shadow/borders are already routed through `--menu-*` tokens. Keep the old class names as compatibility surface.
73
- - `RightMenu`: default classes `.menu-container`, `.menu-button`, `.dropdown-content`, `.menu-item`, `.submenu`, `.draggable-div` live in `src/style/menuRight.css` and already consume `--menu-*` / `--menu-outline-color`.
74
- - `FloatingWindow`: `.wenayWnd*` and `.wenayCloseBtn` live in `src/style/style.css`; defaults intentionally preserve the old transparent/striped window while allowing `--wnd-*` theme overrides.
75
- - `SettingsDialog`: `.wenayDlg*` classes live in `src/style/style.css`; default look is dark and tokenized through `--dlg-*` plus selected `--wnd-*` bridge variables on `.wenayDlgWindow`.
76
- - `Toolbar` / `createToolbar`: `.wenayTb*` classes live in `src/style/style.css`; defaults consume `--tb-*`; stand-specific skins should override through wrapper classes, not by changing shared defaults.
77
- - `Logs`: `src/common/src/logs/logStyles.ts` maps inline logger chrome to `--logs-*`; this is an accepted transitional contract while old logger JSX stays inline-heavy.
78
- - `ColumnDots` / `CardList`: `.wenayColDots*` and `.wenayCardList*` classes live in `src/style/style.css`; restored card-29 defaults are now tokenized through `--cols-dots-*` / `--cols-card-*` with the same fallback values.
79
- - `ColumnsMenu` / `MenuStrip`: behavior is already headless/presentation split. Visual button/container/divider states now use `.wenayColsMenu*` classes and `--cols-menu-*` tokens with the exact previous GitHub-like defaults; runtime reorder transform stays inline.
80
- - `ParamsEditor`: public and still mostly old class + inline style based (`toIndicatorMenuButton`, `miniEl`, `toButtonEasy`, `inputCan`). Do not token-migrate broadly until hook/API direction is decided; candidate prefix `--param-*`.
81
- - `Input` modal helpers: public compatibility helpers over `FloatingWindow`, `.msTradeAlt`, `.msTradeActive`, `.inputCan`, inline panel spacing. Candidate prefix `--input-*`, but may remain compatibility-only if newer app surfaces replace them.
82
-
83
- Done scoped fix:
84
-
85
- - `ColumnsMenu/MenuStrip` visual button/container/divider styles moved to classes/tokens; runtime reorder transform/drag geometry remains inline.
86
-
87
- Done scoped fixes:
88
-
89
- - `ColumnsMenu/MenuStrip` visual button/container/divider styles moved to classes/tokens; runtime reorder transform/drag geometry remains inline.
90
- - `ColumnDots/CardList` restored card-29 defaults moved to `--cols-dots-*` / `--cols-card-*` variables with unchanged fallback values.
91
-
92
- Next scoped candidate:
93
-
94
- - Leave `ParamsEditor` / `Input` broad visual migration until the hook-first/API direction is clearer; only do bug-level style fixes there.
95
- ## 2026-07-09 scoped fix - ColumnsMenu/MenuStrip tokens
96
-
97
- Implemented the compact column menu style contract:
98
-
99
- - Added `--cols-menu-*` defaults to `src/style/tokens.css` and the TS mirror in `src/common/src/styles/tokens.ts`.
100
- - Added `.wenayColsMenu*` classes in `src/style/style.css` for container/list/button states, fixed/drag shadow, text abbreviation, marks, and divider.
101
- - Updated `src/common/src/grid/columnState/ColumnsMenu.tsx` so visual state uses classes; only consumer `style` and `useReorder` runtime transform remain inline.
102
-
103
- Verification: `npx tsc -p tsconfig.qa-check.json --noEmit`; `npm run testjest -- --runInBand`; `npm run build`; `git diff --check`.
104
- ## 2026-07-09 scoped fix - ColumnDots/CardList tokens
105
-
106
- Implemented the mobile/card column-state style contract:
107
-
108
- - Added `--cols-dots-*` and `--cols-card-*` defaults to `src/style/tokens.css` and the TS mirror in `src/common/src/styles/tokens.ts`.
109
- - Rewrote `.wenayColDots*` and `.wenayCardList*` values in `src/style/style.css` to use variables with the exact previous fallbacks.
110
- - Kept component code unchanged; `ColumnDots` runtime geometry (`left`, drag transform) remains inline in the component where it belongs.
111
-
112
- Verification: `npx tsc -p tsconfig.qa-check.json --noEmit`; `npm run testjest -- --runInBand`; `npm run build`; `git diff --check`.
113
- ## 2026-07-09 — Menu default contrast restore
114
-
115
- Сделано:
116
- - `--menu-bg-color` возвращён к непрозрачному dark fallback `#0c0c0c`, `--menu-blur` по умолчанию `0px`;
117
- - добавлены `--menu-item-active-*` и `--menu-item-pressed-*` tokens, старый `--menu-active-background` оставлен alias/fallback;
118
- - `MenuR` / mouse context menu and `RightMenu` CSS получили hard fallbacks: default dark background, white text, hover white with dark text, pressed yellow-ish contrast state;
119
- - причина: рабочие проекты могут ещё не переопределять новые CSS variables, поэтому дефолт не должен становиться glass/transparent.
120
-
121
- Проверка: CSS-only visual contract; прогнать `tsc`/`build`, card 4 вручную открыть правой кнопкой.
1
+ # Style system normalization
2
+
3
+ Status: done/released (v1.0.38, v1.0.39, v1.0.41); default inventory and column-state scoped token fixes implemented and shipped.
4
+
5
+ ## Source
6
+
7
+ User clarification: compatibility can be an aggressive migration when it is
8
+ clearly recorded in changelog, but default styles are dangerous to remove.
9
+ If default styles disappear, the project can become visually broken even when
10
+ the TypeScript/API migration is understandable.
11
+
12
+ ## Standard
13
+
14
+ - Shared primitives must keep a usable default visual style.
15
+ - A default style may be changed, but not silently removed.
16
+ - Removing/replacing a default class requires a replacement class/token path,
17
+ changelog entry, and migration note.
18
+ - New shared visual rules should use CSS custom properties first.
19
+ - Runtime geometry may stay inline when it is state-derived, but color, spacing,
20
+ border, shadow, font, and hover/active states should move to classes/tokens.
21
+ - Apps may override variables; primitives should not require apps to copy a full
22
+ CSS block to remain usable.
23
+
24
+ ## Token direction
25
+
26
+ Current prefixes are a good start:
27
+
28
+ - `--color-*`
29
+ - `--menu-*`
30
+ - `--wnd-*`
31
+ - `--dlg-*`
32
+ - `--tb-*`
33
+ - `--logs-*`
34
+ - `--cols-menu-*` for compact `ColumnsMenu/MenuStrip` visuals.
35
+ - `--cols-dots-*` for `ColumnDots` visuals.
36
+ - `--cols-card-*` for `CardList` visuals.
37
+
38
+ Likely next prefixes:
39
+
40
+ - `--cols-*` remains a family prefix; concrete prefixes now use `--cols-menu-*`, `--cols-dots-*`, and `--cols-card-*`.
41
+ - `--input-*` for generic input/panel defaults if they stay public.
42
+ - `--param-*` for `ParamsEditor` if it remains a shared primitive.
43
+
44
+ ## First audit candidates
45
+
46
+ - `src/style/style.css`: old button/menu classes, `FloatingWindow`, `SettingsDialog`, `Toolbar`, `ColumnDots/CardList`, and raw hover colors.
47
+ - `src/style/menuRight.css`: right-menu visual contract and default state styles.
48
+ - `src/common/src/grid/columnState/*`: finish deciding whether mobile/card
49
+ visuals need `--cols-*` tokens.
50
+ - `src/common/src/components/ParamsEditor.tsx`: move reusable editor visuals
51
+ out of component-owned inline styles if the API remains public.
52
+ - `src/common/src/components/Input.tsx`: decide whether old input panels are
53
+ compatibility-only or need a proper tokenized default.
54
+
55
+ ## Acceptance
56
+
57
+ - Default visual contract documented per public primitive group.
58
+ - Token prefixes chosen before broad style rewrites.
59
+ - No removal of default classes without replacement and changelog.
60
+ - Scoped visual QA cards checked before and after style migration.
61
+ ## 2026-07-09 default style contract inventory
62
+
63
+ Source of truth:
64
+
65
+ - CSS tokens: `src/style/tokens.css`.
66
+ - TS mirror for inline styles/theme builders: `src/common/src/styles/tokens.ts`.
67
+ - Shared runtime CSS: `src/style/style.css` and `src/style/menuRight.css`.
68
+ - Generated `dist/lib/style/*` is build output, not the edit target.
69
+
70
+ Public/default visual contracts:
71
+
72
+ - `Menu` / `MenuR` / mouse context menu: legacy `.MenuR`, `.toButton`, `.toButtonA` classes remain; colors/shadow/borders are already routed through `--menu-*` tokens. Keep the old class names as compatibility surface.
73
+ - `RightMenu`: default classes `.menu-container`, `.menu-button`, `.dropdown-content`, `.menu-item`, `.submenu`, `.draggable-div` live in `src/style/menuRight.css` and already consume `--menu-*` / `--menu-outline-color`.
74
+ - `FloatingWindow`: `.wenayWnd*` and `.wenayCloseBtn` live in `src/style/style.css`; defaults intentionally preserve the old transparent/striped window while allowing `--wnd-*` theme overrides.
75
+ - `SettingsDialog`: `.wenayDlg*` classes live in `src/style/style.css`; default look is dark and tokenized through `--dlg-*` plus selected `--wnd-*` bridge variables on `.wenayDlgWindow`.
76
+ - `Toolbar` / `createToolbar`: `.wenayTb*` classes live in `src/style/style.css`; defaults consume `--tb-*`; stand-specific skins should override through wrapper classes, not by changing shared defaults.
77
+ - `Logs`: `src/common/src/logs/logStyles.ts` maps inline logger chrome to `--logs-*`; this is an accepted transitional contract while old logger JSX stays inline-heavy.
78
+ - `ColumnDots` / `CardList`: `.wenayColDots*` and `.wenayCardList*` classes live in `src/style/style.css`; restored card-29 defaults are now tokenized through `--cols-dots-*` / `--cols-card-*` with the same fallback values.
79
+ - `ColumnsMenu` / `MenuStrip`: behavior is already headless/presentation split. Visual button/container/divider states now use `.wenayColsMenu*` classes and `--cols-menu-*` tokens with the exact previous GitHub-like defaults; runtime reorder transform stays inline.
80
+ - `ParamsEditor`: public and still mostly old class + inline style based (`toIndicatorMenuButton`, `miniEl`, `toButtonEasy`, `inputCan`). Do not token-migrate broadly until hook/API direction is decided; candidate prefix `--param-*`.
81
+ - `Input` modal helpers: public compatibility helpers over `FloatingWindow`, `.msTradeAlt`, `.msTradeActive`, `.inputCan`, inline panel spacing. Candidate prefix `--input-*`, but may remain compatibility-only if newer app surfaces replace them.
82
+
83
+ Done scoped fix:
84
+
85
+ - `ColumnsMenu/MenuStrip` visual button/container/divider styles moved to classes/tokens; runtime reorder transform/drag geometry remains inline.
86
+
87
+ Done scoped fixes:
88
+
89
+ - `ColumnsMenu/MenuStrip` visual button/container/divider styles moved to classes/tokens; runtime reorder transform/drag geometry remains inline.
90
+ - `ColumnDots/CardList` restored card-29 defaults moved to `--cols-dots-*` / `--cols-card-*` variables with unchanged fallback values.
91
+
92
+ Next scoped candidate:
93
+
94
+ - Leave `ParamsEditor` / `Input` broad visual migration until the hook-first/API direction is clearer; only do bug-level style fixes there.
95
+ ## 2026-07-09 scoped fix - ColumnsMenu/MenuStrip tokens
96
+
97
+ Implemented the compact column menu style contract:
98
+
99
+ - Added `--cols-menu-*` defaults to `src/style/tokens.css` and the TS mirror in `src/common/src/styles/tokens.ts`.
100
+ - Added `.wenayColsMenu*` classes in `src/style/style.css` for container/list/button states, fixed/drag shadow, text abbreviation, marks, and divider.
101
+ - Updated `src/common/src/grid/columnState/ColumnsMenu.tsx` so visual state uses classes; only consumer `style` and `useReorder` runtime transform remain inline.
102
+
103
+ Verification: `npx tsc -p tsconfig.qa-check.json --noEmit`; `npm run testjest -- --runInBand`; `npm run build`; `git diff --check`.
104
+ ## 2026-07-09 scoped fix - ColumnDots/CardList tokens
105
+
106
+ Implemented the mobile/card column-state style contract:
107
+
108
+ - Added `--cols-dots-*` and `--cols-card-*` defaults to `src/style/tokens.css` and the TS mirror in `src/common/src/styles/tokens.ts`.
109
+ - Rewrote `.wenayColDots*` and `.wenayCardList*` values in `src/style/style.css` to use variables with the exact previous fallbacks.
110
+ - Kept component code unchanged; `ColumnDots` runtime geometry (`left`, drag transform) remains inline in the component where it belongs.
111
+
112
+ Verification: `npx tsc -p tsconfig.qa-check.json --noEmit`; `npm run testjest -- --runInBand`; `npm run build`; `git diff --check`.
113
+ ## 2026-07-09 — Menu default contrast restore
114
+
115
+ Сделано:
116
+ - `--menu-bg-color` возвращён к непрозрачному dark fallback `#0c0c0c`, `--menu-blur` по умолчанию `0px`;
117
+ - добавлены `--menu-item-active-*` и `--menu-item-pressed-*` tokens, старый `--menu-active-background` оставлен alias/fallback;
118
+ - `MenuR` / mouse context menu and `RightMenu` CSS получили hard fallbacks: default dark background, white text, hover white with dark text, pressed yellow-ish contrast state;
119
+ - причина: рабочие проекты могут ещё не переопределять новые CSS variables, поэтому дефолт не должен становиться glass/transparent.
120
+
121
+ Проверка: CSS-only visual contract; прогнать `tsc`/`build`, card 4 вручную открыть правой кнопкой.
@@ -1,33 +1,33 @@
1
- # Target Backlog Rules
2
-
3
- `doc/target` is the durable task backlog for dictated or imported work. It is not a scratchpad and it is not a changelog.
4
-
5
- ## Files
6
-
7
- - `doc/target/my.md` is the user-owned inbox/queue for dictated tasks. Keep it clean and actionable.
8
- - `target/*.md` are source prompt files imported into this repo. Treat them as task specs; do not edit or delete them just to mark progress unless the user asks for that exact cleanup.
9
- - `doc/progress/*.md` are temporary working notes for an active task. They may be deleted when the task is finished, so they must never be the only place where queue status lives.
10
- - `doc/changes/vX.Y.Z.md` records durable completed changes when code, public docs, theme contracts, dependencies, or policy changed.
11
-
12
- ## Workflow
13
-
14
- 1. When the user says to start from `target`, read this README first, then `doc/target/my.md`, then relevant files under `target/`.
15
- 2. Before coding, normalize dictated text into concrete tasks in `doc/target/my.md`: a short title, current status, source note, and acceptance checks if they are known.
16
- 3. When taking a task, move it to `In Progress` in `doc/target/my.md` and point to the progress file if one is created.
17
- 4. Use `doc/progress/<task>.md` only for checkpoints, decisions, blockers, and verification while work is active.
18
- 5. When implementation is believed complete, move the task to `Verify` in `doc/target/my.md` with the concrete checks that prove it: commands, QA stand checks, screenshots, or manual acceptance points.
19
- 6. Remove a task from `doc/target/my.md` only after `Verify` checks pass and the durable result exists: code/docs are updated, verification is recorded, and changelog is updated when required.
20
- 7. If the task is paused or blocked, leave it in `doc/target/my.md` under `In Progress` or `Blocked` with the next concrete action. Do not delete the progress file in that case.
21
- 8. If a task from `target/*.md` is found already implemented, move it to `Verify` first and check its acceptance criteria before removing it. Do not rely on a deleted progress file as proof.
22
-
23
- ## Status Sections For `my.md`
24
-
25
- Use these sections:
26
-
27
- - `Inbox` - raw or lightly cleaned tasks not yet triaged.
28
- - `Ready` - concrete tasks that can be started.
29
- - `In Progress` - the task currently being worked on, with a progress-file link when applicable.
30
- - `Verify` - implementation is believed complete, but acceptance checks still need to be run or reviewed.
31
- - `Blocked` - tasks waiting for user input, another repository, credentials, or an external change.
32
-
1
+ # Target Backlog Rules
2
+
3
+ `doc/target` is the durable task backlog for dictated or imported work. It is not a scratchpad and it is not a changelog.
4
+
5
+ ## Files
6
+
7
+ - `doc/target/my.md` is the user-owned inbox/queue for dictated tasks. Keep it clean and actionable.
8
+ - `target/*.md` are source prompt files imported into this repo. Treat them as task specs; do not edit or delete them just to mark progress unless the user asks for that exact cleanup.
9
+ - `doc/progress/*.md` are temporary working notes for an active task. They may be deleted when the task is finished, so they must never be the only place where queue status lives.
10
+ - `doc/changes/vX.Y.Z.md` records durable completed changes when code, public docs, theme contracts, dependencies, or policy changed.
11
+
12
+ ## Workflow
13
+
14
+ 1. When the user says to start from `target`, read this README first, then `doc/target/my.md`, then relevant files under `target/`.
15
+ 2. Before coding, normalize dictated text into concrete tasks in `doc/target/my.md`: a short title, current status, source note, and acceptance checks if they are known.
16
+ 3. When taking a task, move it to `In Progress` in `doc/target/my.md` and point to the progress file if one is created.
17
+ 4. Use `doc/progress/<task>.md` only for checkpoints, decisions, blockers, and verification while work is active.
18
+ 5. When implementation is believed complete, move the task to `Verify` in `doc/target/my.md` with the concrete checks that prove it: commands, QA stand checks, screenshots, or manual acceptance points.
19
+ 6. Remove a task from `doc/target/my.md` only after `Verify` checks pass and the durable result exists: code/docs are updated, verification is recorded, and changelog is updated when required.
20
+ 7. If the task is paused or blocked, leave it in `doc/target/my.md` under `In Progress` or `Blocked` with the next concrete action. Do not delete the progress file in that case.
21
+ 8. If a task from `target/*.md` is found already implemented, move it to `Verify` first and check its acceptance criteria before removing it. Do not rely on a deleted progress file as proof.
22
+
23
+ ## Status Sections For `my.md`
24
+
25
+ Use these sections:
26
+
27
+ - `Inbox` - raw or lightly cleaned tasks not yet triaged.
28
+ - `Ready` - concrete tasks that can be started.
29
+ - `In Progress` - the task currently being worked on, with a progress-file link when applicable.
30
+ - `Verify` - implementation is believed complete, but acceptance checks still need to be run or reviewed.
31
+ - `Blocked` - tasks waiting for user input, another repository, credentials, or an external change.
32
+
33
33
  Completed tasks are normally removed from `my.md`; the final response, commit message, and changelog carry the durable completion record.
@@ -554,6 +554,9 @@ useReplayHistory(history, apply, {head?, reset?, tickMs?=300, autoPlay?=true})
554
554
  -> {live, seq, head, pause(), play(), seek({seq?|ts?})}
555
555
  ```
556
556
  Semantics that are easy to get wrong:
557
+ - **Identity and reconnect boundary (common2 1.0.75).** `remote` identifies one logical Replay line. A temporary Socket.IO disconnect/reconnect keeps that object identity, so the React effect stays mounted while common2 rebinds the physical Listen subscription, restores live delivery first, catches up from its private `lastDelivered seq`, drains the racing queue, and deduplicates. Do not call `restart()`, remount with a new key, replace `remote`, poll, or attach transport listeners in React. The retained journal must cover the cursor; a sacred-line eviction with no keyframe is terminal `error`/`onError`, never a silent reset to `since: 0` or latest. `policy: 'queue'` is lossless and must deliver every retained event exactly once; `policy: 'frame'` is explicitly lossy/conflated and is not a journal-integrity check.
558
+ **Identity matrix**
559
+ - **Hard teardown is intentional.** `client.close()`/`dispose()` and hub `connect()`/`setToken()` end the old logical generation. React must clean up normally and must not resurrect that subscription automatically; after an intentional new client or credentials generation, provide its new `remote` as a normal new subscription. Ordinary RPC/pipe calls are not replayed by this contract.
557
560
  - `cb`/`apply` go through refs: new function identity does NOT resubscribe. Resubscribe identity is `[remote, enabled, epoch, staleMs, policy]` — changing `staleMs` resubscribes (it is subscribe-time config in common2; under keepSeq the reconnect is a journal tail, so it is cheap); `policy` picks the wire surface (line vs frameLine), so it resubscribes too. `onStale` goes through a ref like `cb`.
558
561
  - Route hand-off hooks (`useReplayRouteSubscribe`, `useStoreReplayRouteSync`, `useStoreReplayRouteMirror`) wrap common2 `Replay.replayRouteSubscribe` / `Observe.syncStoreReplayRoute`: `switchRoute(nextRemote, {label?, since?, reset?, policy?, hint?})` keeps the old route live, catches up the replacement from the last delivered `seq`, then closes the old route. Failed replacement leaves the old route active and surfaces `error` / `route.phase == "error"`. Changing the `remote` prop is still treated as a fresh subscription boundary; no-gap promotion/demotion is explicit through `switchRoute()`. common2 1.0.65 route handles expose `seq()`, `label()`, and `active()`, but not `isStale()` / `lastTs()`, so route hooks deliberately do not promise freshness yet.
559
562
  - Lag policy / hint (frame model, common2 rev2): `policy: 'frame'` rides the server's `frameLine` when the remote has one — on lag the server drops for THIS client and recovers via the line's `frame` lambda (mini-frame); without a frameLine (old server, in-proc `exposeReplay`) common2 silently degrades to `'queue'`, so an in-proc QA of `'frame'` proves nothing — the wire test lives in common2 (`replay/rpc-auto.test.ts`). `hint` is opaque to the transport and goes through a ref: in `useReplaySubscribe` it is captured at subscribe time (used for the catch-up `frame()` call); in `useReplayFrame` it is read on EVERY pull, so a new identity is never missed and never resubscribes.
@@ -478,7 +478,7 @@ Conference composition ships as a live example: `wenay-react2/demo/peer-conferen
478
478
 
479
479
  Media lines (common2 1.0.66 `Media.createAudioSource` / `Media.createVideoSource`) are ordinary binary Listen sources; with `replay:true` their `listen` is a replay line, so `useReplaySubscribe` / `useReplayFrame` consume mic/camera frames with no media-specific hook. `useMediaSource(kind, options)` is only the capture lifecycle adapter (`start`, `stop`, device selection, state and stats); it stops a started source on unmount and returns `listen` unchanged. Each frame is one `Uint8Array` (`Media.decodeMediaFrame`); draw/play it via ref (canvas, AudioContext), never useState — the same rule as any high-frequency line. Without `replay`, the plain `listen` works with the listen hooks above.
480
480
 
481
- Contract: `off()` on unmount, StrictMode-safe; seq survives resubscribes inside one mount (keepSeq, default on) — a resubscribe reconnects with `{since}` and gets the journal tail, not a keyframe. Across a FULL unmount/remount keep the position outside via `onSeq` and pass it back as `since`. `seq()` is a getter — high-frequency lines (video frames, ticks) do not re-render per event; draw to canvas via ref, bypassing VDOM. Freshness: detection lives in wenay-common2 (`staleMs` watchdog); the non-route hooks mirror its edge-triggered `onStale` into `stale`, so a fresh 100 ev/s line causes zero extra renders. Route hand-off is explicit through `switchRoute(nextRemote, {label?, since?, reset?, policy?, hint?})`: old route stays live while the replacement catches up by `seq`, then closes. `useReplayHistory` is archive playback — staleness does not apply. QA cards 23 (video line + conflation + time travel + freshness), 24 (store sync), 25 (per-key feed), and 26 (route hand-off) are the live examples.
481
+ Contract: `off()` on unmount, StrictMode-safe; seq survives resubscribes inside one mount (keepSeq, default on) — a resubscribe reconnects with `{since}` and gets the journal tail, not a keyframe. Across a FULL unmount/remount keep the position outside via `onSeq` and pass it back as `since`. With `wenay-common2@^1.0.75`, a temporary RPC transport disconnect/reconnect keeps the same logical `remote`: common2 rebinds its physical Listen subscription, catches up from its own last delivered seq, and deduplicates racing live events. React must not call `restart()`, remount, change a key, or add Socket.IO listeners for that case. `policy: "queue"` is the lossless choice; `"frame"` is deliberately conflated. A retained-history gap without a keyframe is a terminal `error`, not a fresh start. Deliberate `client.dispose()`/`close()` and hub `connect()`/`setToken()` are hard teardown boundaries, not auto-reconnects. `seq()` is a getter — high-frequency lines (video frames, ticks) do not re-render per event; draw to canvas via ref, bypassing VDOM. Freshness: detection lives in wenay-common2 (`staleMs` watchdog); the non-route hooks mirror its edge-triggered `onStale` into `stale`, so a fresh 100 ev/s line causes zero extra renders. Route hand-off is explicit through `switchRoute(nextRemote, {label?, since?, reset?, policy?, hint?})`: old route stays live while the replacement catches up by `seq`, then closes. `useReplayHistory` is archive playback — staleness does not apply. QA cards 23 (video line + conflation + time travel + freshness), 24 (store sync), 25 (per-key feed), and 26 (route hand-off) are the live examples.
482
482
 
483
483
  ## Logs
484
484
  ```
@@ -53,6 +53,7 @@ export function useReplaySubscribe(remote, cb, options = {}) {
53
53
  seqRef.current = undefined; // a different line — old seq is meaningless
54
54
  lastRemoteRef.current = remote;
55
55
  let alive = true;
56
+ let failed = false;
56
57
  setReady(false);
57
58
  setError(null);
58
59
  // stale is NOT reset here: it re-syncs from common2 after the first delivery (a stale
@@ -68,8 +69,11 @@ export function useReplaySubscribe(remote, cb, options = {}) {
68
69
  hooksRef.current.onSeq?.(seq);
69
70
  },
70
71
  onError: e => {
71
- if (alive)
72
+ failed = true;
73
+ if (alive) {
72
74
  setError(e);
75
+ setReady(false);
76
+ }
73
77
  hooksRef.current.onError?.(e);
74
78
  },
75
79
  ...(staleMs !== undefined ? {
@@ -83,7 +87,7 @@ export function useReplaySubscribe(remote, cb, options = {}) {
83
87
  });
84
88
  subRef.current = off;
85
89
  off.ready.then(() => {
86
- if (!alive)
90
+ if (!alive || failed)
87
91
  return;
88
92
  setReady(true);
89
93
  if (staleMs !== undefined)