Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG NODE_VERSION=22
ARG NODE_VERSION=24
FROM node:${NODE_VERSION} AS builder
WORKDIR /app

Expand Down
52 changes: 52 additions & 0 deletions docs/explorations/2026-10-18-assistant-design-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,55 @@ stronger fill.
announcing streamed tokens would break INTERACTION §3's "do not announce every streamed
character". Adding one needs a design decision about what a polite announcement says when
the answer is still being written.

## Screenshot follow-up: text insets, disclosures and action affordances

The screenshot review exposed five remaining usability defects. This follow-up starts
from document `d8ce247e` and ran `d7e324cc`; each repository carries its own PR and
retains separate implementation and regression-test commits.

| Reported symptom | Reproduced cause | Change and owner |
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| Header title touches its hover background | The text button has no inline padding | document: an 8px inline inset with ellipsis for long titles |
| Suggested task text touches both edges | Task rows use vertical padding only | document: 12px inline padding, an explicit border and surface fill |
| Speech privacy disclosure is too far above the icon | Application code adds a second upward translation after ranui positions the popup; the measured gap is about 52px | document: remove the extra translation and use the component's 8px anchor gap |
| Language menu and privacy disclosure overlap | Both controls can retain `open`; bubble-phase outside listeners also miss propagation-stopping clicks | document: mutually exclusive public `show`/`open` handling; ran: shared capture-based outside dismissal |
| Artifact import looks like ordinary text | The action has no border or fill; its form inherits the borderless artifact editor treatment | document: distinguish workspace actions and give the import form visible field labels, borders and text insets |

The same review covered adjacent workspace actions, model settings, sources, artifacts,
composer controls, focus rings and touch geometry. The assistant enable switch keeps its
compact 40×24px track inside a 48×32px button, growing to at least 44px tall for coarse
pointers. The structured-import title field also retains a 44px touch target after being
wrapped in a visible label. Existing native labels, accessible names and disabled states
remain in use.

The ran fix belongs to the shared floating controller rather than an application-specific
position override. Outside clicks dismiss sibling Select/Popover controls in either order;
clicks inside a nested portaled menu preserve its ancestor. A node-owned `Symbol.for`
records logical ownership across independently loaded component bundles. Local shadow-root
capture classifies events hidden by a closed root, while a document fallback handles clicks
outside that root. Listener teardown and pending fallback decisions are guarded against
disconnection and newer open/close transitions.

Verification for the application follow-up:

- Full unit suite: 252 files, 6,799 tests passed.
- Browser regression after the stable dependency upgrade: 47 tests passed, covering the
screenshot cases, sidebar layout, workspace consistency, dictation, history and themes.
- Rendered checks include 360px/1280px, light/dark, keyboard activation/Escape/focus return,
touch hit targets, import validation and popup anchor distance.
- The registry-backed frozen install, production build, type checking, Docker configuration
and repository archive/format checks passed, including 1,511 immutable evaluation records.

The application disclosure coordination uses existing public APIs and was first validated
against the pinned `ranui@0.5.0-alpha.6`. The shared floating fix was merged in
[ran PR #428](https://github.com/chaxus/ran/pull/428) and released through the
[verified release workflow](https://github.com/chaxus/ran/actions/runs/39140435475).
Document now pins `ranui@0.5.0` and `ranuts@0.5.0` throughout its consuming workspaces;
ranui brings `@alixex/ranview@0.2.0` transitively. Its checked-in token stylesheet and
standalone component bundles are regenerated by `bin/build.sh` from the installed release.

The published libraries require Node 24+, so the application engine requirement and Docker
builder move to Node 24 as well. This is a build-toolchain requirement; the application
continues to run in the browser. Model requests, persistence formats and account-free
frontend operation are unaffected.
14 changes: 10 additions & 4 deletions lib/agent-plugin/ui/artifacts-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,16 +434,22 @@ export function createArtifactsView(options: {
const data = document.createElement('textarea');
data.maxLength = 262144;
const importForm = document.createElement('div');
importForm.className = 'agent-artifact-editor';
importForm.className = 'agent-artifact-editor agent-artifact-import';
body.append(importForm);
data.setAttribute('aria-label', labels.import);
data.placeholder = labels.importHint;
data.placeholder = labels.import;
const hint = document.createElement('p');
hint.textContent = labels.importHint;
importForm.append(
title,
View('label')
.class('agent-artifact-import-field')
.children(View('span').text(labels.titleField), title)
.build(),
hint,
data,
View('label')
.class('agent-artifact-import-field')
.children(View('span').text(labels.import), data)
.build(),
button('saveNew', () => {
void perform(async () => {
let envelope: { schemaVersion?: unknown; payload?: unknown };
Expand Down
8 changes: 2 additions & 6 deletions lib/agent-plugin/ui/speech-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,6 @@ export function mountSpeechInput(chat: SpeechComposer, allowed: () => boolean) {
const bindPopup = () => {
const popup = privacy.popoverContent;
if (!popup) return;
// Keep the disclosure above the whole draft rather than over editable text.
const composer = root.closest('.cui-composer');
if (composer) {
const clearance = privacy.getBoundingClientRect().top - composer.getBoundingClientRect().top;
popup.style.translate = `0 ${-Math.max(0, clearance)}px`;
}
if (popup === boundPopup) return;
boundPopup = popup;
popup.classList.add('agent-speech-popover');
Expand Down Expand Up @@ -132,10 +126,12 @@ export function mountSpeechInput(chat: SpeechComposer, allowed: () => boolean) {
scheduleDisclosure();
};
privacy.addEventListener('show', () => {
language.removeAttribute('open');
privacyToggle.setAttribute('aria-expanded', 'true');
bindPopup();
scheduleDisclosure();
});
language.addEventListener('show', () => privacy.removeAttribute('open'));
privacy.addEventListener('hide', () => {
privacyToggle.setAttribute('aria-expanded', 'false');
pauseDisclosure();
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"test:archive": "node bin/evaluation-archive.mjs"
},
"engines": {
"node": ">=20.19.0"
"node": ">=24.0.0"
},
"keywords": [
"onlyoffice",
Expand Down Expand Up @@ -81,7 +81,7 @@
"@ranuts/converter": "workspace:*",
"@ranuts/shared": "workspace:*",
"pdfjs-dist": "5.4.624",
"ranui": "0.5.0-alpha.6",
"ranuts": "0.4.1-alpha.2"
"ranui": "0.5.0",
"ranuts": "0.5.0"
}
}
4 changes: 2 additions & 2 deletions packages/chat-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
},
"dependencies": {
"marked": "16.4.2",
"ranui": "0.5.0-alpha.6",
"ranuts": "0.4.1-alpha.2"
"ranui": "0.5.0",
"ranuts": "0.5.0"
},
"devDependencies": {
"typescript": "^6.0.3"
Expand Down
4 changes: 2 additions & 2 deletions packages/converter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
},
"dependencies": {
"@ranuts/shared": "workspace:*",
"ranui": "0.5.0-alpha.6",
"ranuts": "0.4.1-alpha.2"
"ranui": "0.5.0",
"ranuts": "0.5.0"
},
"devDependencies": {
"typescript": "^6.0.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"prepare": "tsc -p tsconfig.json"
},
"dependencies": {
"ranuts": "0.4.1-alpha.2"
"ranuts": "0.5.0"
},
"devDependencies": {
"typescript": "^6.0.3"
Expand Down
Loading
Loading