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 2 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,18 @@ final class ViewFocusBinding {
_onViewCreatedListener?.cancel();
}

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

if (state == ui.ViewFocusState.focused) {
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