Skip to content

Commit

Permalink
Poc
Browse files Browse the repository at this point in the history
  • Loading branch information
oleq committed Oct 11, 2023
1 parent e86147a commit 32715de
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
cursor: default;
min-width: 12em;

&.ck-list__item_selected {
background: var(--ck-color-list-button-hover-background);
}

& .ck-button {
min-height: unset;
width: 100%;
Expand Down
43 changes: 41 additions & 2 deletions packages/ckeditor5-ui/src/autocomplete/autocompleteview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getOptimalPosition, type PositioningFunction, type Locale, global, toUn
import SearchTextView, { type SearchTextViewConfig } from '../search/text/searchtextview';
import type SearchResultsView from '../search/searchresultsview';
import type InputBase from '../input/inputbase';
import type { FilteredViewExecuteEvent } from '../search/filteredview';
import type { FilteredViewExecuteEvent, FilteredViewSelectEvent } from '../search/filteredview';

import '../../theme/components/autocomplete/autocomplete.css';

Expand Down Expand Up @@ -83,6 +83,7 @@ export default class AutocompleteView<
this.on( 'search', () => {
this._updateResultsVisibility();
this._updateResultsViewWidthAndPosition();
this.filteredView.resetSelect();
} );

// Hide the results view when the user presses the ESC key.
Expand All @@ -91,6 +92,35 @@ export default class AutocompleteView<
cancel();
} );

this.keystrokes.set( 'arrowdown', ( evt, cancel ) => {
if ( this.resultsView.isVisible ) {
this.filteredView.selectNext();
} else {
this.resultsView.isVisible = true;
this.search( this.queryView.fieldView.element!.value );
}

cancel();
} );

this.keystrokes.set( 'arrowup', ( evt, cancel ) => {
if ( this.resultsView.isVisible ) {
this.filteredView.selectPrevious();
} else {
this.resultsView.isVisible = true;
this.search( this.queryView.fieldView.element!.value );
}

cancel();
} );

this.keystrokes.set( 'enter', ( evt, cancel ) => {
if ( this.resultsView.isVisible ) {
this.resultsView.isVisible = false;
cancel();
}
} );

// Update the position of the results view when the user scrolls the page.
// TODO: This needs to be debounced down the road.
this.listenTo( global.document, 'scroll', () => {
Expand Down Expand Up @@ -120,9 +150,18 @@ export default class AutocompleteView<
this.resultsView.isVisible = false;
} );

this.filteredView.on<FilteredViewSelectEvent>( 'select', ( evt, { selectedValue } ) => {
// Update the value of the query field.
this.queryView.fieldView.value = this.queryView.fieldView.element!.value = selectedValue;
} );

// Update the position and width of the results view when it becomes visible.
this.resultsView.on( 'change:isVisible', () => {
this.resultsView.on( 'change:isVisible', ( evt, name, isVisible ) => {
this._updateResultsViewWidthAndPosition();

if ( !isVisible ) {
this.filteredView.resetSelect();
}
} );
}

Expand Down
9 changes: 8 additions & 1 deletion packages/ckeditor5-ui/src/list/listitemview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export default class ListItemView extends View {
*/
declare public isVisible: boolean;

/**
* @inheritDoc
*/
declare public isSelected: boolean;

/**
* @inheritDoc
*/
Expand All @@ -41,6 +46,7 @@ export default class ListItemView extends View {
const bind = this.bindTemplate;

this.set( 'isVisible', true );
this.set( 'isSelected', false );

this.children = this.createCollection();

Expand All @@ -51,7 +57,8 @@ export default class ListItemView extends View {
class: [
'ck',
'ck-list__item',
bind.if( 'isVisible', 'ck-hidden', value => !value )
bind.if( 'isVisible', 'ck-hidden', value => !value ),
bind.if( 'isSelected', 'ck-list__item_selected' )
],
role: 'presentation'
},
Expand Down
85 changes: 82 additions & 3 deletions packages/ckeditor5-ui/src/list/listview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import View from '../view';
import FocusCycler from '../focuscycler';

import type ListItemView from './listitemview';
import ListItemView from './listitemview';
import ListItemGroupView from './listitemgroupview';
import type DropdownPanelFocusable from '../dropdown/dropdownpanelfocusable';
import ViewCollection from '../viewcollection';
Expand All @@ -20,10 +20,12 @@ import {
KeystrokeHandler,
type Locale,
type GetCallback,
type CollectionChangeEvent
type CollectionChangeEvent,
isVisible
} from '@ckeditor/ckeditor5-utils';

import '../../theme/components/list/list.css';
import ViewCycler from '../viewcycler';

/**
* The list view class.
Expand All @@ -34,7 +36,7 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown
* between the {@link module:ui/list/listitemview~ListItemView list items} and
* {@link module:ui/list/listitemgroupview~ListItemGroupView list groups}.
*/
public readonly focusables: ViewCollection;
public readonly focusables: ViewCollection<ListItemView | ListItemGroupView>;

/**
* Collection of the child list views.
Expand Down Expand Up @@ -77,6 +79,11 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown
*/
private readonly _focusCycler: FocusCycler;

/**
* TODO
*/
private readonly _viewCycler: ViewCycler;

/**
* A cached map of {@link module:ui/list/listitemgroupview~ListItemGroupView} to `change` event listeners for their `items`.
* Used for accessibility and keyboard navigation purposes.
Expand All @@ -95,6 +102,11 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown
this.items = this.createCollection();
this.focusTracker = new FocusTracker();
this.keystrokes = new KeystrokeHandler();
this._viewCycler = new ViewCycler( {
views: this.focusables,
viewsFilter: ( view: View ) => view instanceof ListItemView && isVisible( view.element ),
currentViewFilter: ( view: View ) => ( view as ListItemView ).isSelected
} );

this._focusCycler = new FocusCycler( {
focusables: this.focusables,
Expand Down Expand Up @@ -199,6 +211,61 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown
this._focusCycler.focusLast();
}

/**
* TODO
*/
public selectPrevious(): ListItemView | null {
const previousListItemView = this._viewCycler.previous! as ListItemView | null;

if ( previousListItemView ) {
this.resetSelect();

previousListItemView.isSelected = true;
previousListItemView.element!.scrollIntoView( { block: 'nearest', inline: 'nearest' } );

this.fire<ListViewSelectEvent>( 'select', {
listItemView: previousListItemView
} );

return previousListItemView;
}

return null;
}

/**
* TODO
*/
public selectNext(): ListItemView | null {
const nextListItemView = this._viewCycler.next! as ListItemView | null;

if ( nextListItemView ) {
this.resetSelect();

nextListItemView.isSelected = true;
nextListItemView.element!.scrollIntoView( { block: 'nearest', inline: 'nearest' } );

this.fire<ListViewSelectEvent>( 'select', {
listItemView: nextListItemView
} );

return nextListItemView;
}

return null;
}

/**
* TODO
*/
public resetSelect(): void {
const currentListItemView = this._viewCycler.current as ListItemView | null;

if ( currentListItemView ) {
currentListItemView.isSelected = false;
}
}

/**
* Registers a list item view in the focus tracker.
*
Expand Down Expand Up @@ -277,3 +344,15 @@ export default class ListView extends View<HTMLUListElement> implements Dropdown

// There's no support for nested groups yet.
type ListItemsChangeEvent = CollectionChangeEvent<ListItemView>;

/**
* TODO
*
* @eventName ~ListView#select
*/
export interface ListViewSelectEvent {
name: 'select';
args: [ {
listItemView: ListItemView;
} ];
}
20 changes: 19 additions & 1 deletion packages/ckeditor5-ui/src/search/filteredview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,32 @@ export default interface FilteredView extends FocusableView {
resultsCount: number;
totalItemsCount: number;
};

selectNext(): void;

selectPrevious(): void;

resetSelect(): void;
}

/**
* Fired when the user selects an autocomplete option. The event data should contain the selected value.
* Fired when the user picks an autocomplete option (e.g. by clicking on it). The event data should contain the selected value.
*
* @eventName ~FilteredView#execute
*/
export interface FilteredViewExecuteEvent {
name: 'execute';
args: [ { value: string } ];
}

/**
* Fired when the user selects an autocomplete option (e.g. by using arrow keys). The event data should contain the selected value.
*
* @eventName ~FilteredView#select
*/
export interface FilteredViewSelectEvent {
name: 'select';
args: [ {
selectedValue: any;
} ];
}
Loading

0 comments on commit 32715de

Please sign in to comment.