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
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ ts_library(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
deps = ["@npm//@angular/core"],
deps = [
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Signal} from '@angular/core';
import {SignalLike} from '../signal-like/signal-like';
import {
EventHandler,
EventHandlerOptions,
Expand All @@ -20,9 +20,9 @@ import {
* Used to represent a keycode.
*
* This is used to match whether an events keycode should be handled. The ability to match using a
* string, Signal, or Regexp gives us more flexibility when authoring event handlers.
* string, SignalLike, or Regexp gives us more flexibility when authoring event handlers.
*/
type KeyCode = string | Signal<string> | RegExp;
type KeyCode = string | SignalLike<string> | RegExp;

/**
* An event manager that is specialized for handling keyboard events. By default this manager stops
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ts_library(
),
deps = [
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"@npm//@angular/core",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)

Expand All @@ -20,6 +20,7 @@ ng_test_library(
deps = [
":list-focus",
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {computed, Signal, signal} from '@angular/core';
import {computed, signal} from '@angular/core';
import {SignalLike} from '../signal-like/signal-like';
import {ListNavigation, ListNavigationInputs} from '../list-navigation/list-navigation';
import {ListFocus, ListFocusInputs, ListFocusItem} from './list-focus';

describe('List Focus', () => {
interface TestItem extends ListFocusItem {
tabindex: Signal<-1 | 0>;
tabindex: SignalLike<-1 | 0>;
}

function getItems(length: number): Signal<TestItem[]> {
function getItems(length: number): SignalLike<TestItem[]> {
return signal(
Array.from({length}).map((_, i) => ({
index: signal(i),
Expand All @@ -28,7 +29,7 @@ describe('List Focus', () => {
}

function getNavigation<T extends TestItem>(
items: Signal<T[]>,
items: SignalLike<T[]>,
args: Partial<ListNavigationInputs<T>> = {},
): ListNavigation<T> {
return new ListNavigation({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Signal} from '@angular/core';
import {SignalLike} from '../signal-like/signal-like';
import {ListNavigation, ListNavigationItem} from '../list-navigation/list-navigation';

/** Represents an item in a collection, such as a listbox option, than may receive focus. */
export interface ListFocusItem extends ListNavigationItem {
/** A unique identifier for the item. */
id: Signal<string>;
id: SignalLike<string>;

/** The html element that should receive focus. */
element: Signal<HTMLElement>;
element: SignalLike<HTMLElement>;
}

/** Represents the required inputs for a collection that contains focusable items. */
export interface ListFocusInputs<T extends ListFocusItem> {
/** The focus strategy used by the list. */
focusMode: Signal<'roving' | 'activedescendant'>;
focusMode: SignalLike<'roving' | 'activedescendant'>;
}

/** Controls focus for a list of items. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ ts_library(
["**/*.ts"],
exclude = ["**/*.spec.ts"],
),
deps = ["@npm//@angular/core"],
deps = [
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
"@npm//@angular/core",
],
)

ng_test_library(
name = "unit_test_sources",
srcs = glob(["**/*.spec.ts"]),
deps = [":list-navigation"],
deps = [
":list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)

ng_web_test_suite(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Signal, signal, WritableSignal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike, WritableSignalLike} from '../signal-like/signal-like';
import {ListNavigationItem, ListNavigation, ListNavigationInputs} from './list-navigation';

describe('List Navigation', () => {
interface TestItem extends ListNavigationItem {
disabled: WritableSignal<boolean>;
disabled: WritableSignalLike<boolean>;
}

function getItems(length: number): Signal<TestItem[]> {
function getItems(length: number): SignalLike<TestItem[]> {
return signal(
Array.from({length}).map((_, i) => ({
index: signal(i),
Expand All @@ -24,7 +25,7 @@ describe('List Navigation', () => {
}

function getNavigation<T extends TestItem>(
items: Signal<T[]>,
items: SignalLike<T[]>,
args: Partial<ListNavigationInputs<T>> = {},
): ListNavigation<T> {
return new ListNavigation({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,34 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {signal, Signal, WritableSignal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike, WritableSignalLike} from '../signal-like/signal-like';

/** Represents an item in a collection, such as a listbox option, than can be navigated to. */
export interface ListNavigationItem {
/** Whether an item is disabled. */
disabled: Signal<boolean>;
disabled: SignalLike<boolean>;
}

/** Represents the required inputs for a collection that has navigable items. */
export interface ListNavigationInputs<T extends ListNavigationItem> {
/** Whether focus should wrap when navigating. */
wrap: Signal<boolean>;
wrap: SignalLike<boolean>;

/** The items in the list. */
items: Signal<T[]>;
items: SignalLike<T[]>;

/** Whether disabled items in the list should be skipped when navigating. */
skipDisabled: Signal<boolean>;
skipDisabled: SignalLike<boolean>;

/** The current index that has been navigated to. */
activeIndex: WritableSignal<number>;
activeIndex: WritableSignalLike<number>;

/** Whether the list is vertically or horizontally oriented. */
orientation: Signal<'vertical' | 'horizontal'>;
orientation: SignalLike<'vertical' | 'horizontal'>;

/** The direction that text is read based on the users locale. */
textDirection: Signal<'rtl' | 'ltr'>;
textDirection: SignalLike<'rtl' | 'ltr'>;
}

/** Controls navigation for a list of items. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ts_library(
),
deps = [
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
"@npm//@angular/core",
],
)
Expand All @@ -20,6 +21,7 @@ ng_test_library(
deps = [
":list-selection",
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Signal, signal, WritableSignal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike, WritableSignalLike} from '../signal-like/signal-like';
import {ListSelectionItem, ListSelection, ListSelectionInputs} from './list-selection';
import {ListNavigation, ListNavigationInputs} from '../list-navigation/list-navigation';

describe('List Selection', () => {
interface TestItem extends ListSelectionItem {
disabled: WritableSignal<boolean>;
disabled: WritableSignalLike<boolean>;
}

function getItems(length: number): Signal<TestItem[]> {
function getItems(length: number): SignalLike<TestItem[]> {
return signal(
Array.from({length}).map((_, i) => ({
index: signal(i),
Expand All @@ -27,7 +28,7 @@ describe('List Selection', () => {
}

function getNavigation<T extends TestItem>(
items: Signal<T[]>,
items: SignalLike<T[]>,
args: Partial<ListNavigationInputs<T>> = {},
): ListNavigation<T> {
return new ListNavigation({
Expand All @@ -42,7 +43,7 @@ describe('List Selection', () => {
}

function getSelection<T extends TestItem>(
items: Signal<T[]>,
items: SignalLike<T[]>,
navigation: ListNavigation<T>,
args: Partial<ListSelectionInputs<T>> = {},
): ListSelection<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,32 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {signal, Signal, WritableSignal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike, WritableSignalLike} from '../signal-like/signal-like';
import {ListNavigation, ListNavigationItem} from '../list-navigation/list-navigation';

/** Represents an item in a collection, such as a listbox option, than can be selected. */
export interface ListSelectionItem extends ListNavigationItem {
/** A unique identifier for the item. */
id: Signal<string>;
id: SignalLike<string>;

/** Whether an item is disabled. */
disabled: Signal<boolean>;
disabled: SignalLike<boolean>;
}

/** Represents the required inputs for a collection that contains selectable items. */
export interface ListSelectionInputs<T extends ListSelectionItem> {
/** The items in the list. */
items: Signal<T[]>;
items: SignalLike<T[]>;

/** Whether multiple items in the list can be selected at once. */
multiselectable: Signal<boolean>;
multiselectable: SignalLike<boolean>;

/** The ids of the current selected items. */
selectedIds: WritableSignal<string[]>;
selectedIds: WritableSignalLike<string[]>;

/** The selection strategy used by the list. */
selectionMode: Signal<'follow' | 'explicit'>;
selectionMode: SignalLike<'follow' | 'explicit'>;
}

/** Controls selection for a list of items. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ ts_library(
),
deps = [
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
"@npm//@angular/core",
],
)
Expand All @@ -20,6 +21,7 @@ ng_test_library(
deps = [
":list-typeahead",
"//src/cdk-experimental/ui-patterns/behaviors/list-navigation",
"//src/cdk-experimental/ui-patterns/behaviors/signal-like",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Signal, signal, WritableSignal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike, WritableSignalLike} from '../signal-like/signal-like';
import {ListTypeaheadItem, ListTypeahead} from './list-typeahead';
import {fakeAsync, tick} from '@angular/core/testing';
import {ListNavigation} from '../list-navigation/list-navigation';

describe('List Typeahead', () => {
interface TestItem extends ListTypeaheadItem {
disabled: WritableSignal<boolean>;
disabled: WritableSignalLike<boolean>;
}

function getItems(length: number): Signal<TestItem[]> {
function getItems(length: number): SignalLike<TestItem[]> {
return signal(
Array.from({length}).map((_, i) => ({
index: signal(i),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {signal, Signal} from '@angular/core';
import {signal} from '@angular/core';
import {SignalLike} from '../signal-like/signal-like';
import {ListNavigationItem, ListNavigation} from '../list-navigation/list-navigation';

/**
Expand All @@ -15,7 +16,7 @@ import {ListNavigationItem, ListNavigation} from '../list-navigation/list-naviga
*/
export interface ListTypeaheadItem extends ListNavigationItem {
/** The text used by the typeahead search. */
searchTerm: Signal<string>;
searchTerm: SignalLike<string>;
}

/**
Expand All @@ -24,7 +25,7 @@ export interface ListTypeaheadItem extends ListNavigationItem {
*/
export interface ListTypeaheadInputs {
/** The amount of time before the typeahead search is reset. */
typeaheadDelay: Signal<number>;
typeaheadDelay: SignalLike<number>;
}

/** Controls typeahead for a list of items. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("//tools:defaults.bzl", "ts_library")

package(default_visibility = ["//visibility:public"])

ts_library(
name = "signal-like",
srcs = ["signal-like.ts"],
deps = [],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/

export type SignalLike<T> = () => T;

export interface WritableSignalLike<T> extends SignalLike<T> {
set(value: T): void;
update(updateFn: (value: T) => T): void;
}

/** Converts a getter setter style signal to a WritableSignalLike. */
export function convertGetterSetterToWritableSignalLike<T>(
getter: () => T,
setter: (v: T) => void,
): WritableSignalLike<T> {
// tslint:disable-next-line:ban Have to use `Object.assign` to preserve the getter function.
return Object.assign(getter, {
set: setter,
update: (updateCallback: (v: T) => T) => setter(updateCallback(getter())),
});
}
Loading
Loading