Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
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 lib/web_ui/lib/src/engine/platform_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
required ui.ViewFocusState state,
required ui.ViewFocusDirection direction,
}) {
// TODO(tugorez): implement this method. At the moment will be a no op call.
_viewFocusBinding.changeViewFocus(viewId, state);
}

/// A set of views which have rendered in the current `onBeginFrame` or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ final class ViewFocusBinding {
_onViewCreatedListener?.cancel();
}

void changeViewFocus(int viewId, ui.ViewFocusState state) {
final DomElement? viewElement = _viewManager[viewId]?.dom.rootElement;

if (state == ui.ViewFocusState.focused) {
// Only move the focus to the flutter view if nothing inside it is focused already.
if (viewId != _viewId(domDocument.activeElement)) {
viewElement?.focus();
}
} else {
viewElement?.blur();
}
}

late final DomEventListener _handleFocusin = createDomEventListener((DomEvent event) {
event as DomFocusEvent;
_handleFocusChange(event.target as DomElement?);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,108 @@ void testMain() {
expect(dispatchedViewFocusEvents[2].state, ui.ViewFocusState.unfocused);
expect(dispatchedViewFocusEvents[2].direction, ui.ViewFocusDirection.undefined);
});

test('requestViewFocusChange focuses the view', () {
final EngineFlutterView view = createAndRegisterView(dispatcher);

dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);

expect(domDocument.activeElement, view.dom.rootElement);

expect(dispatchedViewFocusEvents, hasLength(1));

expect(dispatchedViewFocusEvents[0].viewId, view.viewId);
expect(dispatchedViewFocusEvents[0].state, ui.ViewFocusState.focused);
expect(dispatchedViewFocusEvents[0].direction, ui.ViewFocusDirection.forward);
});

test('requestViewFocusChange blurs the view', () {
final EngineFlutterView view = createAndRegisterView(dispatcher);

dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);

dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.unfocused,
direction: ui.ViewFocusDirection.undefined,
);

expect(domDocument.activeElement, isNot(view.dom.rootElement));

expect(dispatchedViewFocusEvents, hasLength(2));

expect(dispatchedViewFocusEvents[0].viewId, view.viewId);
expect(dispatchedViewFocusEvents[0].state, ui.ViewFocusState.focused);
expect(dispatchedViewFocusEvents[0].direction, ui.ViewFocusDirection.forward);

expect(dispatchedViewFocusEvents[1].viewId, view.viewId);
expect(dispatchedViewFocusEvents[1].state, ui.ViewFocusState.unfocused);
expect(dispatchedViewFocusEvents[1].direction, ui.ViewFocusDirection.undefined);
});

test('requestViewFocusChange does nothing if the view does not exist', () {
final EngineFlutterView view = createAndRegisterView(dispatcher);

dispatcher.requestViewFocusChange(
viewId: 5094555,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);

expect(domDocument.activeElement, isNot(view.dom.rootElement));
expect(dispatchedViewFocusEvents, isEmpty);
});

test('requestViewFocusChange does nothing if the view is already focused', () {
final EngineFlutterView view = createAndRegisterView(dispatcher);

dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);
dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);

expect(dispatchedViewFocusEvents, hasLength(1));

expect(dispatchedViewFocusEvents[0].viewId, view.viewId);
expect(dispatchedViewFocusEvents[0].state, ui.ViewFocusState.focused);
expect(dispatchedViewFocusEvents[0].direction, ui.ViewFocusDirection.forward);
});

test('requestViewFocusChange does not move the focus to the view', () {
final DomElement input = createDomElement('input');
final EngineFlutterView view = createAndRegisterView(dispatcher);

view.dom.rootElement.append(input);
input.focus();

dispatcher.requestViewFocusChange(
viewId: view.viewId,
state: ui.ViewFocusState.focused,
direction: ui.ViewFocusDirection.forward,
);

expect(domDocument.activeElement, input);

expect(dispatchedViewFocusEvents, hasLength(1));

expect(dispatchedViewFocusEvents[0].viewId, view.viewId);
expect(dispatchedViewFocusEvents[0].state, ui.ViewFocusState.focused);
expect(dispatchedViewFocusEvents[0].direction, ui.ViewFocusDirection.forward);
});
});
}

Expand Down